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

#include "debuggermanager.h"

#include "debuggerconstants.h"
#include "idebuggerengine.h"

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

#include "ui_breakbyfunction.h"

#include "disassemblerhandler.h"
#include "breakhandler.h"
#include "moduleshandler.h"
#include "registerhandler.h"
#include "stackhandler.h"
#include "watchhandler.h"

#include "debuggerdialogs.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
#ifdef Q_OS_WIN
#  include "peutils.h"
#endif
#include <utils/qtcassert.h>

con's avatar
con committed
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QTime>
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/QMainWindow>
#include <QtGui/QMessageBox>
#include <QtGui/QPlainTextEdit>
#include <QtGui/QStatusBar>
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
#include <QtGui/QToolBar>
#include <QtGui/QToolButton>
#include <QtGui/QToolTip>

using namespace Debugger;
using namespace Debugger::Internal;
using namespace Debugger::Constants;

static const QString tooltipIName = "tooltip";


DebuggerSettings::DebuggerSettings()
{
    m_autoRun = false;
    m_autoQuit = false;
    m_skipKnownFrames = false;
    m_debugDumpers = false;
    m_useToolTips = false;
    m_useCustomDumpers = true;
    m_listSourceFiles = false;
con's avatar
con committed
///////////////////////////////////////////////////////////////////////
//
// BreakByFunctionDialog
//
///////////////////////////////////////////////////////////////////////

class BreakByFunctionDialog : public QDialog, Ui::BreakByFunctionDialog
{
    Q_OBJECT

public:
    explicit BreakByFunctionDialog(QWidget *parent)
      : QDialog(parent)
    {
        setupUi(this);
        connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
        connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
    }
    QString functionName() const { return functionLineEdit->text(); }
};


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

static IDebuggerEngine *gdbEngine = 0;
static IDebuggerEngine *winEngine = 0;
static IDebuggerEngine *scriptEngine = 0;

extern IDebuggerEngine *createGdbEngine(DebuggerManager *parent);
extern IDebuggerEngine *createWinEngine(DebuggerManager *)
#ifdef CDB_ENABLED
;
#else
{ return 0; }
#endif
con's avatar
con committed
extern IDebuggerEngine *createScriptEngine(DebuggerManager *parent);

DebuggerManager::DebuggerManager() :
    m_attachCoreAction(0)
con's avatar
con committed
{
    init();
}

DebuggerManager::~DebuggerManager()
{
    delete gdbEngine;
    delete winEngine;
    delete scriptEngine;
}

void DebuggerManager::init()
{
    m_status = -1;
    m_busy = false;

    m_attachedPID = 0;
    m_startMode = StartInternal;
con's avatar
con committed

    m_disassemblerHandler = 0;
    m_modulesHandler = 0;
    m_registerHandler = 0;

    m_statusLabel = new QLabel;
con's avatar
con committed
    m_breakWindow = new BreakWindow;
    m_disassemblerWindow = new DisassemblerWindow;
    m_modulesWindow = new ModulesWindow;
    m_outputWindow = new DebuggerOutputWindow;
    m_registerWindow = new RegisterWindow;
    m_stackWindow = new StackWindow;
    m_sourceFilesWindow = new SourceFilesWindow;
con's avatar
con committed
    m_threadsWindow = new ThreadsWindow;
    m_localsWindow = new WatchWindow(WatchWindow::LocalsType);
    m_watchersWindow = new WatchWindow(WatchWindow::WatchersType);
    //m_tooltipWindow = new WatchWindow(WatchWindow::TooltipType);
    //m_watchersWindow = new QTreeView;
    m_tooltipWindow = new QTreeView;
    m_statusTimer = new QTimer(this);
con's avatar
con committed

    m_mainWindow = new QMainWindow;
    m_mainWindow->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
    m_mainWindow->setDocumentMode(true);

    // Stack
    m_stackHandler = new StackHandler;
    QAbstractItemView *stackView =
        qobject_cast<QAbstractItemView *>(m_stackWindow);
    stackView->setModel(m_stackHandler->stackModel());
    connect(stackView, SIGNAL(frameActivated(int)),
        this, SLOT(activateFrame(int)));

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

    // Disassembler
    m_disassemblerHandler = new DisassemblerHandler;
    QAbstractItemView *disassemblerView =
        qobject_cast<QAbstractItemView *>(m_disassemblerWindow);
    disassemblerView->setModel(m_disassemblerHandler->model());

    // Breakpoints
    m_breakHandler = new BreakHandler;
    QAbstractItemView *breakView =
        qobject_cast<QAbstractItemView *>(m_breakWindow);
    breakView->setModel(m_breakHandler->model());
    connect(breakView, SIGNAL(breakpointActivated(int)),
        m_breakHandler, SLOT(activateBreakpoint(int)));
    connect(breakView, SIGNAL(breakpointDeleted(int)),
con's avatar
con committed
        m_breakHandler, SLOT(removeBreakpoint(int)));
    connect(breakView, SIGNAL(settingsDialogRequested()),
        this, SIGNAL(settingsDialogRequested()));
    connect(breakView, SIGNAL(breakpointSynchronizationRequested()),
        this, SLOT(attemptBreakpointSynchronization()));
con's avatar
con committed
    connect(m_breakHandler, SIGNAL(gotoLocation(QString,int,bool)),
        this, SLOT(gotoLocation(QString,int,bool)));
    connect(m_breakHandler, SIGNAL(sessionValueRequested(QString,QVariant*)),
        this, SIGNAL(sessionValueRequested(QString,QVariant*)));
    connect(m_breakHandler, SIGNAL(setSessionValueRequested(QString,QVariant)),
        this, SIGNAL(setSessionValueRequested(QString,QVariant)));

    // Modules
    QAbstractItemView *modulesView =
        qobject_cast<QAbstractItemView *>(m_modulesWindow);
    m_modulesHandler = new ModulesHandler;
    modulesView->setModel(m_modulesHandler->model());
    connect(modulesView, SIGNAL(reloadModulesRequested()),
        this, SLOT(reloadModules()));
    connect(modulesView, SIGNAL(loadSymbolsRequested(QString)),
        this, SLOT(loadSymbols(QString)));
    connect(modulesView, SIGNAL(loadAllSymbolsRequested()),
        this, SLOT(loadAllSymbols()));

    // Source Files
    //m_sourceFilesHandler = new SourceFilesHandler;
    QAbstractItemView *sourceFilesView =
        qobject_cast<QAbstractItemView *>(m_sourceFilesWindow);
    //sourceFileView->setModel(m_stackHandler->stackModel());
    connect(sourceFilesView, SIGNAL(reloadSourceFilesRequested()),
        this, SLOT(reloadSourceFiles()));
con's avatar
con committed

    // Registers 
    QAbstractItemView *registerView =
        qobject_cast<QAbstractItemView *>(m_registerWindow);
    m_registerHandler = new RegisterHandler;
    registerView->setModel(m_registerHandler->model());

    m_watchHandler = new WatchHandler;

    // Locals
    QTreeView *localsView = qobject_cast<QTreeView *>(m_localsWindow);
    localsView->setModel(m_watchHandler->model());
    connect(localsView, SIGNAL(requestExpandChildren(QModelIndex)),
        this, SLOT(expandChildren(QModelIndex)));
    connect(localsView, SIGNAL(requestCollapseChildren(QModelIndex)),
        this, SLOT(collapseChildren(QModelIndex)));
    connect(localsView, SIGNAL(requestAssignValue(QString,QString)),
        this, SLOT(assignValueInDebugger(QString,QString)));
    connect(localsView, SIGNAL(requestWatchExpression(QString)),
        this, SLOT(watchExpression(QString)));
    connect(localsView, SIGNAL(settingsDialogRequested()),
        this, SIGNAL(settingsDialogRequested()));
con's avatar
con committed

    // Watchers 
    QTreeView *watchersView = qobject_cast<QTreeView *>(m_watchersWindow);
    watchersView->setModel(m_watchHandler->model());
    connect(watchersView, SIGNAL(requestAssignValue(QString,QString)),
        this, SLOT(assignValueInDebugger(QString,QString)));
    connect(watchersView, SIGNAL(requestExpandChildren(QModelIndex)),
        this, SLOT(expandChildren(QModelIndex)));
    connect(watchersView, SIGNAL(requestCollapseChildren(QModelIndex)),
        this, SLOT(collapseChildren(QModelIndex)));
    connect(watchersView, SIGNAL(requestWatchExpression(QString)),
        this, SLOT(watchExpression(QString)));
    connect(watchersView, SIGNAL(requestRemoveWatchExpression(QString)),
        this, SLOT(removeWatchExpression(QString)));
    connect(m_watchHandler, SIGNAL(sessionValueRequested(QString,QVariant*)),
        this, SIGNAL(sessionValueRequested(QString,QVariant*)));
    connect(m_watchHandler, SIGNAL(setSessionValueRequested(QString,QVariant)),
        this, SIGNAL(setSessionValueRequested(QString,QVariant)));
    connect(watchersView, SIGNAL(settingsDialogRequested()),
        this, SIGNAL(settingsDialogRequested()));
con's avatar
con committed

    // Tooltip
    QTreeView *tooltipView = qobject_cast<QTreeView *>(m_tooltipWindow);
    tooltipView->setModel(m_watchHandler->model());

    connect(m_watchHandler, SIGNAL(watchModelUpdateRequested()),
        this, SLOT(updateWatchModel()));

    m_startExternalAction = new QAction(this);
    m_startExternalAction->setText(tr("Start and Debug External Application..."));

    m_attachExternalAction = new QAction(this);
    m_attachExternalAction->setText(tr("Attach to Running External Application..."));

#ifndef Q_OS_WIN
    m_attachCoreAction = new QAction(this);
    m_attachCoreAction->setText(tr("Attach to Core..."));
    connect(m_attachCoreAction, SIGNAL(triggered()), this, SLOT(attachCore()));
#endif
con's avatar
con committed
    m_continueAction = new QAction(this);
    m_continueAction->setText(tr("Continue"));
    m_continueAction->setIcon(QIcon(":/gdbdebugger/images/debugger_continue_small.png"));

    m_stopAction = new QAction(this);
    m_stopAction->setText(tr("Interrupt"));
    m_stopAction->setIcon(QIcon(":/gdbdebugger/images/debugger_interrupt_small.png"));

    m_resetAction = new QAction(this);
    m_resetAction->setText(tr("Reset Debugger"));

    m_nextAction = new QAction(this);
    m_nextAction->setText(tr("Step Over"));
    //m_nextAction->setShortcut(QKeySequence(tr("F6")));
    m_nextAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stepover_small.png"));

    m_stepAction = new QAction(this);
    m_stepAction->setText(tr("Step Into"));
    //m_stepAction->setShortcut(QKeySequence(tr("F7")));
    m_stepAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stepinto_small.png"));

    m_nextIAction = new QAction(this);
    m_nextIAction->setText(tr("Step Over Instruction"));
    //m_nextIAction->setShortcut(QKeySequence(tr("Shift+F6")));
    m_nextIAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stepoverproc_small.png"));

    m_stepIAction = new QAction(this);
    m_stepIAction->setText(tr("Step One Instruction"));
    //m_stepIAction->setShortcut(QKeySequence(tr("Shift+F9")));
    m_stepIAction->setIcon(QIcon(":/gdbdebugger/images/debugger_steponeproc_small.png"));

    m_stepOutAction = new QAction(this);
    m_stepOutAction->setText(tr("Step Out"));
    //m_stepOutAction->setShortcut(QKeySequence(tr("Shift+F7")));
    m_stepOutAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stepout_small.png"));

    m_runToLineAction = new QAction(this);
    m_runToLineAction->setText(tr("Run to Line"));

    m_runToFunctionAction = new QAction(this);
    m_runToFunctionAction->setText(tr("Run to Outermost Function"));

    m_jumpToLineAction = new QAction(this);
    m_jumpToLineAction->setText(tr("Jump to Line"));

    m_breakAction = new QAction(this);
    m_breakAction->setText(tr("Toggle Breakpoint"));

    m_breakByFunctionAction = new QAction(this);
    m_breakByFunctionAction->setText(tr("Set Breakpoint at Function..."));

    m_breakAtMainAction = new QAction(this);
    m_breakAtMainAction->setText(tr("Set Breakpoint at Function \"main\""));
con's avatar
con committed

    m_watchAction = new QAction(this);
    m_watchAction->setText(tr("Add to Watch Window"));

    // For usuage hints oin focus{In,Out}
    //connect(m_outputWindow, SIGNAL(statusMessageRequested(QString,int)),
    //    this, SLOT(showStatusMessage(QString,int)));

    connect(m_continueAction, SIGNAL(triggered()),
        this, SLOT(continueExec()));

    connect(m_startExternalAction, SIGNAL(triggered()),
        this, SLOT(startExternalApplication()));
    connect(m_attachExternalAction, SIGNAL(triggered()),
        this, SLOT(attachExternalApplication()));

    connect(m_stopAction, SIGNAL(triggered()),
        this, SLOT(interruptDebuggingRequest()));
    connect(m_resetAction, SIGNAL(triggered()),
        this, SLOT(exitDebugger()));
    connect(m_nextAction, SIGNAL(triggered()),
        this, SLOT(nextExec()));
    connect(m_stepAction, SIGNAL(triggered()),
        this, SLOT(stepExec()));
    connect(m_nextIAction, SIGNAL(triggered()),
        this, SLOT(nextIExec()));
    connect(m_stepIAction, SIGNAL(triggered()),
        this, SLOT(stepIExec()));
    connect(m_stepOutAction, SIGNAL(triggered()),
        this, SLOT(stepOutExec()));
    connect(m_runToLineAction, SIGNAL(triggered()),
        this, SLOT(runToLineExec()));
    connect(m_runToFunctionAction, SIGNAL(triggered()),
        this, SLOT(runToFunctionExec()));
    connect(m_jumpToLineAction, SIGNAL(triggered()),
        this, SLOT(jumpToLineExec()));
    connect(m_watchAction, SIGNAL(triggered()),
        this, SLOT(addToWatchWindow()));
    connect(m_breakAction, SIGNAL(triggered()),
        this, SLOT(toggleBreakpoint()));
    connect(m_breakByFunctionAction, SIGNAL(triggered()),
        this, SLOT(breakByFunction()));
    connect(m_breakAtMainAction, SIGNAL(triggered()),
        this, SLOT(breakAtMain()));

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

    connect(m_outputWindow, SIGNAL(commandExecutionRequested(QString)),
        this, SLOT(executeDebuggerCommand(QString)));


    m_breakDock = createDockForWidget(m_breakWindow);

    m_disassemblerDock = createDockForWidget(m_disassemblerWindow);
    connect(m_disassemblerDock->toggleViewAction(), SIGNAL(toggled(bool)),
        this, SLOT(reloadDisassembler()), Qt::QueuedConnection);

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

    m_registerDock = createDockForWidget(m_registerWindow);
    connect(m_registerDock->toggleViewAction(), SIGNAL(toggled(bool)),
        this, SLOT(reloadRegisters()), Qt::QueuedConnection);

    m_outputDock = createDockForWidget(m_outputWindow);

    m_stackDock = createDockForWidget(m_stackWindow);

    m_sourceFilesDock = createDockForWidget(m_sourceFilesWindow);
    connect(m_sourceFilesDock->toggleViewAction(), SIGNAL(toggled(bool)),
        this, SLOT(reloadSourceFiles()), Qt::QueuedConnection);

con's avatar
con committed
    m_threadsDock = createDockForWidget(m_threadsWindow);

    setStatus(DebuggerProcessNotReady);
    gdbEngine = createGdbEngine(this);
    winEngine = createWinEngine(this);
    scriptEngine = createScriptEngine(this);
    setDebuggerType(GdbDebugger);
Friedemann Kleint's avatar
Friedemann Kleint committed
    if (Debugger::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << gdbEngine << winEngine << scriptEngine;
con's avatar
con committed
}

void DebuggerManager::setDebuggerType(DebuggerType type)
{
    switch (type) {
        case GdbDebugger:
            m_engine = gdbEngine;
            break;
        case ScriptDebugger:
            m_engine = scriptEngine;
            break;
        case WinDebugger:
            m_engine = winEngine;
            break;
    }
}

IDebuggerEngine *DebuggerManager::engine()
{
    return m_engine;
}

IDebuggerManagerAccessForEngines *DebuggerManager::engineInterface()
{
    return dynamic_cast<IDebuggerManagerAccessForEngines *>(this);
}

void DebuggerManager::createDockWidgets()
{
    QSplitter *localsAndWatchers = new QSplitter(Qt::Vertical, 0);
    localsAndWatchers->setWindowTitle(m_localsWindow->windowTitle());
    localsAndWatchers->addWidget(m_localsWindow);
    localsAndWatchers->addWidget(m_watchersWindow);
    localsAndWatchers->setStretchFactor(0, 3);
    localsAndWatchers->setStretchFactor(1, 1);
    m_watchDock = createDockForWidget(localsAndWatchers);
}

QDockWidget *DebuggerManager::createDockForWidget(QWidget *widget)
{
    QDockWidget *dockWidget = new QDockWidget(widget->windowTitle(), m_mainWindow);
    dockWidget->setObjectName(widget->windowTitle());
    dockWidget->setFeatures(QDockWidget::DockWidgetClosable);
con's avatar
con committed
    dockWidget->setTitleBarWidget(new QWidget(dockWidget));
    dockWidget->setWidget(widget);
    connect(dockWidget->toggleViewAction(), SIGNAL(toggled(bool)),
        this, SLOT(dockToggled(bool)), Qt::QueuedConnection);
    m_dockWidgets.append(dockWidget);
    return dockWidget;
}

void DebuggerManager::setSimpleDockWidgetArrangement()
{
    foreach (QDockWidget *dockWidget, m_dockWidgets)
        m_mainWindow->removeDockWidget(dockWidget);

    foreach (QDockWidget *dockWidget, m_dockWidgets) {
        m_mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
        dockWidget->show();
    }

    m_mainWindow->tabifyDockWidget(m_watchDock, m_breakDock);
    m_mainWindow->tabifyDockWidget(m_watchDock, m_disassemblerDock);
    m_mainWindow->tabifyDockWidget(m_watchDock, m_modulesDock);
    m_mainWindow->tabifyDockWidget(m_watchDock, m_outputDock);
    m_mainWindow->tabifyDockWidget(m_watchDock, m_registerDock);
    m_mainWindow->tabifyDockWidget(m_watchDock, m_threadsDock);
    m_mainWindow->tabifyDockWidget(m_watchDock, m_sourceFilesDock);
con's avatar
con committed

    // They are rarely used even in ordinary debugging. Hiding them also saves
    // cycles since the corresponding information won't be retrieved.
    m_sourceFilesDock->hide();
con's avatar
con committed
    m_registerDock->hide();
    m_disassemblerDock->hide();
    m_modulesDock->hide();
    m_outputDock->hide();
}

void DebuggerManager::setLocked(bool locked)
{
    const QDockWidget::DockWidgetFeatures features =
            (locked) ? QDockWidget::DockWidgetClosable :
con's avatar
con committed
                       QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable;

    foreach (QDockWidget *dockWidget, m_dockWidgets) {
        QWidget *titleBarWidget = dockWidget->titleBarWidget();
        if (locked && !titleBarWidget)
            titleBarWidget = new QWidget(dockWidget);
        else if (!locked && titleBarWidget) {
            delete titleBarWidget;
            titleBarWidget = 0;
        }
        dockWidget->setTitleBarWidget(titleBarWidget);
        dockWidget->setFeatures(features);
    }
}

void DebuggerManager::dockToggled(bool on)
{
    QDockWidget *dw = qobject_cast<QDockWidget *>(sender()->parent());
    if (on && dw)
        dw->raise();
}

QAbstractItemModel *DebuggerManager::threadsModel()
{
    return qobject_cast<ThreadsWindow*>(m_threadsWindow)->model();
}

void DebuggerManager::clearStatusMessage()
{
    m_statusLabel->setText(m_lastPermanentStatusMessage);
}

con's avatar
con committed
void DebuggerManager::showStatusMessage(const QString &msg, int timeout)
{
    Q_UNUSED(timeout)
Friedemann Kleint's avatar
Friedemann Kleint committed
    if (Debugger::Constants::Internal::debug)
        qDebug() << "STATUS MSG: " << msg;
con's avatar
con committed
    showDebuggerOutput("status:", msg);
    m_statusLabel->setText("   " + msg);
    if (timeout > 0) {
        m_statusTimer->setSingleShot(true);
        m_statusTimer->start(timeout);
    } else {
        m_lastPermanentStatusMessage = msg;
        m_statusTimer->stop();
    }
con's avatar
con committed
}

void DebuggerManager::notifyInferiorStopRequested()
{
    setStatus(DebuggerInferiorStopRequested);
    showStatusMessage(tr("Stop requested..."), 5000);
}

con's avatar
con committed
void DebuggerManager::notifyInferiorStopped()
{
    resetLocation();
    setStatus(DebuggerInferiorStopped);
    showStatusMessage(tr("Stopped."), 5000);
}

void DebuggerManager::notifyInferiorRunningRequested()
{
    setStatus(DebuggerInferiorRunningRequested);
    showStatusMessage(tr("Running requested..."), 5000);
con's avatar
con committed
}

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

void DebuggerManager::notifyInferiorExited()
{
    setStatus(DebuggerProcessNotReady);
con's avatar
con committed
    showStatusMessage(tr("Stopped."), 5000);
}

void DebuggerManager::notifyInferiorPidChanged(int pid)
{
Friedemann Kleint's avatar
Friedemann Kleint committed
    if (Debugger::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << pid;
con's avatar
con committed
    //QMessageBox::warning(0, "PID", "PID: " + QString::number(pid)); 
    emit inferiorPidChanged(pid);
}

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

void DebuggerManager::shutdown()
{
Friedemann Kleint's avatar
Friedemann Kleint committed
    if (Debugger::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << m_engine;

    if (m_engine)
        m_engine->shutdown();
    m_engine = 0;

    delete scriptEngine;
    scriptEngine = 0;
    delete gdbEngine;
    gdbEngine = 0;
    delete winEngine;
    winEngine = 0;

con's avatar
con committed
    // Delete these manually before deleting the manager
    // (who will delete the models for most views)
    delete m_breakWindow;
    delete m_disassemblerWindow;
    delete m_modulesWindow;
    delete m_outputWindow;
    delete m_registerWindow;
    delete m_stackWindow;
    delete m_sourceFilesWindow;
con's avatar
con committed
    delete m_threadsWindow;
    delete m_tooltipWindow;
    delete m_watchersWindow;
    delete m_localsWindow;
    // These widgets are all in some layout which will take care of deletion.
    m_breakWindow = 0;
    m_disassemblerWindow = 0;
    m_modulesWindow = 0;
    m_outputWindow = 0;
    m_registerWindow = 0;
    m_stackWindow = 0;
    m_sourceFilesWindow = 0;
con's avatar
con committed
    m_threadsWindow = 0;
    m_tooltipWindow = 0;
    m_watchersWindow = 0;
    m_localsWindow = 0;

    delete m_breakHandler;
    delete m_disassemblerHandler;
dt's avatar
dt committed
    delete m_threadsHandler;
con's avatar
con committed
    delete m_modulesHandler;
    delete m_registerHandler;
    delete m_stackHandler;
    delete m_watchHandler;
    m_breakHandler = 0;
    m_disassemblerHandler = 0;
dt's avatar
dt committed
    m_threadsHandler = 0;
con's avatar
con committed
    m_modulesHandler = 0;
    m_registerHandler = 0;
    m_stackHandler = 0;
    m_watchHandler = 0;
    //qDebug() << "DEBUGGER_MANAGER SHUTDOWN END";
}

void DebuggerManager::toggleBreakpoint()
{
    QString fileName;
    int lineNumber = -1;
    queryCurrentTextEditor(&fileName, &lineNumber, 0);
    if (lineNumber == -1)
        return;
    toggleBreakpoint(fileName, lineNumber);
}

void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber)
{
Friedemann Kleint's avatar
Friedemann Kleint committed
    if (Debugger::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << fileName << lineNumber;

    QTC_ASSERT(m_engine, return);
    QTC_ASSERT(m_breakHandler, return);
    if (status() != DebuggerInferiorRunning
         && status() != DebuggerInferiorStopped 
         && status() != DebuggerProcessNotReady) {
        showStatusMessage(tr("Changing breakpoint state requires either a "
            "fully running or fully stopped application."));
        return;
    }

con's avatar
con committed
    int index = m_breakHandler->indexOf(fileName, lineNumber);
    if (index == -1)
        m_breakHandler->setBreakpoint(fileName, lineNumber);
con's avatar
con committed
    else
        m_breakHandler->removeBreakpoint(index);
    m_engine->attemptBreakpointSynchronization();
con's avatar
con committed
}

void DebuggerManager::attemptBreakpointSynchronization()
{
    m_engine->attemptBreakpointSynchronization();
}

con's avatar
con committed
void DebuggerManager::setToolTipExpression(const QPoint &pos, const QString &exp)
{
    QTC_ASSERT(m_engine, return);
    m_engine->setToolTipExpression(pos, exp);
con's avatar
con committed
}

void DebuggerManager::updateWatchModel()
{
    QTC_ASSERT(m_engine, return);
    m_engine->updateWatchModel();
con's avatar
con committed
}

void DebuggerManager::expandChildren(const QModelIndex &idx)
{
    QTC_ASSERT(m_watchHandler, return);
    m_watchHandler->expandChildren(idx);
con's avatar
con committed
}

void DebuggerManager::collapseChildren(const QModelIndex &idx)
{
    QTC_ASSERT(m_watchHandler, return);
    m_watchHandler->collapseChildren(idx);
con's avatar
con committed
}

void DebuggerManager::removeWatchExpression(const QString &exp)
con's avatar
con committed
{
    QTC_ASSERT(m_watchHandler, return);
    m_watchHandler->removeWatchExpression(exp);
con's avatar
con committed
}

QVariant DebuggerManager::sessionValue(const QString &name)
{
    // this is answered by the plugin
con's avatar
con committed
    QVariant value;
    emit sessionValueRequested(name, &value);
    return value;
}

void DebuggerManager::querySessionValue(const QString &name, QVariant *value)
{
    // this is answered by the plugin
con's avatar
con committed
    emit sessionValueRequested(name, value);
}

void DebuggerManager::setSessionValue(const QString &name, const QVariant &value)
{
    // this is answered by the plugin
con's avatar
con committed
    emit setSessionValueRequested(name, value);
}

QVariant DebuggerManager::configValue(const QString &name)
{
    // this is answered by the plugin
con's avatar
con committed
    QVariant value;
    emit configValueRequested(name, &value);
    return value;
}

void DebuggerManager::queryConfigValue(const QString &name, QVariant *value)
{
    // this is answered by the plugin
con's avatar
con committed
    emit configValueRequested(name, value);
}

void DebuggerManager::setConfigValue(const QString &name, const QVariant &value)
{
    // this is answered by the plugin
con's avatar
con committed
    emit setConfigValueRequested(name, value);
}

void DebuggerManager::startExternalApplication()
{
    if (!startNewDebugger(StartExternal))
con's avatar
con committed
        emit debuggingFinished();
}

void DebuggerManager::attachExternalApplication()
{
    if (!startNewDebugger(AttachExternal))
con's avatar
con committed
        emit debuggingFinished();
}

void DebuggerManager::attachCore()
{
    if (!startNewDebugger(AttachCore))
        emit debuggingFinished();
}

// Figure out the debugger type of an executable
Friedemann Kleint's avatar
Friedemann Kleint committed
static bool determineDebuggerType(const QString &executable,
                                  DebuggerManager::DebuggerType *dt,
                                  QString *errorMessage)
{
    if (executable.endsWith(QLatin1String(".js"))) {
        *dt = DebuggerManager::ScriptDebugger;
        return true;
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
    *dt = DebuggerManager::GdbDebugger;
Friedemann Kleint's avatar
Friedemann Kleint committed
    return true;
#else
    // If a file has PDB files, it has been compiled by VS.
    QStringList pdbFiles;
    if (!getPDBFiles(executable, &pdbFiles, errorMessage))
        return false;
    if (pdbFiles.empty()) {
        *dt = DebuggerManager::GdbDebugger;
        return true;
    }
    // We need the CDB debugger in order to be able to debug VS
    // executables
    if (!winEngine) {
        *errorMessage = DebuggerManager::tr("Debugging VS executables is not supported.");
        return false;
    }
    *dt = DebuggerManager::WinDebugger;
    return true;
#endif
}

// Figure out the debugger type of a PID
static bool determineDebuggerType(int  /* pid */,
                                  DebuggerManager::DebuggerType *dt,
                                  QString * /*errorMessage*/)
{
#ifdef Q_OS_WIN
    // Preferably Windows debugger
    *dt = winEngine ? DebuggerManager::WinDebugger : DebuggerManager::GdbDebugger;
#else
    *dt = DebuggerManager::GdbDebugger;
#endif
    return true;
}

bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
con's avatar
con committed
{
Friedemann Kleint's avatar
Friedemann Kleint committed
    if (Debugger::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO << mode;

con's avatar
con committed
    m_startMode = mode;
    // FIXME: Clean up

    switch  (startMode()) {
    case StartExternal: {
con's avatar
con committed
        StartExternalDialog dlg(mainWindow());
        dlg.setExecutableFile(
            configValue(QLatin1String("LastExternalExecutableFile")).toString());
        dlg.setExecutableArguments(
            configValue(QLatin1String("LastExternalExecutableArguments")).toString());
        if (dlg.exec() != QDialog::Accepted)
            return false;
        setConfigValue(QLatin1String("LastExternalExecutableFile"),
            dlg.executableFile());
        setConfigValue(QLatin1String("LastExternalExecutableArguments"),
            dlg.executableArguments());
        m_executable = dlg.executableFile();
        m_processArgs = dlg.executableArguments().split(' ');
        m_workingDir = QString();
        m_attachedPID = -1;
    }
        break;
    case AttachExternal: {
        AttachExternalDialog dlg(mainWindow());
con's avatar
con committed
        if (dlg.exec() != QDialog::Accepted)
            return false;
        m_executable = QString();
        m_processArgs = QStringList();
        m_workingDir = QString();
        m_attachedPID = dlg.attachPID();
        if (m_attachedPID == 0) {
            QMessageBox::warning(mainWindow(), tr("Warning"),
                tr("Cannot attach to PID 0"));
            return false;
        }
    }
        break;
    case StartInternal:
con's avatar
con committed
        if (m_executable.isEmpty()) {
            QString startDirectory = m_executable;
            if (m_executable.isEmpty()) {
                QString fileName;
                emit currentTextEditorRequested(&fileName, 0, 0);
                if (!fileName.isEmpty()) {
                    const QFileInfo editorFile(fileName);
                    startDirectory = editorFile.dir().absolutePath();
                }
            }
            StartExternalDialog dlg(mainWindow());
            dlg.setExecutableFile(startDirectory);
            if (dlg.exec() != QDialog::Accepted)
                return false;
            m_executable = dlg.executableFile();
            m_processArgs = dlg.executableArguments().split(' ');
            m_workingDir = QString();
            m_attachedPID = 0;
        } else {
            //m_executable = QDir::convertSeparators(m_executable);
            //m_processArgs = sd.processArgs.join(QLatin1String(" "));
            m_attachedPID = 0;
        }
        break;
    case AttachCore: {
        AttachCoreDialog dlg(mainWindow());
        dlg.setExecutableFile(
            configValue(QLatin1String("LastExternalExecutableFile")).toString());
        dlg.setCoreFile(
            configValue(QLatin1String("LastExternalCoreFile")).toString());
        if (dlg.exec() != QDialog::Accepted)
            return false;
        setConfigValue(QLatin1String("LastExternalExecutableFile"),
            dlg.executableFile());
        setConfigValue(QLatin1String("LastExternalCoreFile"),
            dlg.coreFile());
        m_executable = dlg.executableFile();
        m_coreFile = dlg.coreFile();
        m_processArgs.clear();
        m_workingDir = QString();
        m_attachedPID = -1;
con's avatar
con committed
    }
con's avatar
con committed

    emit debugModeRequested();

Friedemann Kleint's avatar
Friedemann Kleint committed
    DebuggerType type;
    QString errorMessage;
    const bool hasDebugger = startMode() == AttachExternal ?
         determineDebuggerType(m_attachedPID, &type, &errorMessage) :
         determineDebuggerType(m_executable, &type, &errorMessage);
    if (!hasDebugger) {
Friedemann Kleint's avatar
Friedemann Kleint committed
        QMessageBox::warning(mainWindow(), tr("Warning"),
                tr("Cannot debug '%1': %2").arg(m_executable, errorMessage));
        return false;

    }
    if (Debugger::Constants::Internal::debug)
        qDebug() << m_executable << type;
con's avatar
con committed

Friedemann Kleint's avatar
Friedemann Kleint committed
    setDebuggerType(type);
    setStatus(DebuggerProcessStartingUp);
    if (!m_engine->startDebugger()) {
        setStatus(DebuggerProcessNotReady);
con's avatar
con committed
        return false;
con's avatar
con committed

    m_busy = false;
    return true;
}

void DebuggerManager::cleanupViews()
{
    resetLocation();
    breakHandler()->setAllPending();
    stackHandler()->removeAll();
    threadsHandler()->removeAll();
    disassemblerHandler()->removeAll();
    modulesHandler()->removeAll();
    watchHandler()->cleanup();
    m_sourceFilesWindow->removeAll();
con's avatar
con committed
}

void DebuggerManager::exitDebugger()
{
Friedemann Kleint's avatar
Friedemann Kleint committed
    if (Debugger::Constants::Internal::debug)
        qDebug() << Q_FUNC_INFO;

hjk's avatar
hjk committed
    if (m_engine)
        m_engine->exitDebugger();
con's avatar
con committed
    cleanupViews();
    setStatus(DebuggerProcessNotReady);
    setBusyCursor(false);
    emit debuggingFinished();
}

void DebuggerManager::assignValueInDebugger(const QString &expr, const QString &value)
{
    QTC_ASSERT(m_engine, return);
    m_engine->assignValueInDebugger(expr, value);
con's avatar
con committed
}

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