Newer
Older
/**************************************************************************
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
** 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.
**************************************************************************/
#include "debuggerrunner.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"
#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 <coreplugin/icore.h>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QTimer>
#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/QPushButton>
#include <QtGui/QToolTip>
using namespace Debugger;
using namespace Debugger::Internal;
using namespace Debugger::Constants;
static const QString tooltipIName = "tooltip";
static const char *stateName(int s)
{
switch (s) {
case DebuggerProcessNotReady:
return "DebuggerProcessNotReady";
case DebuggerProcessStartingUp:
return "DebuggerProcessStartingUp";
case DebuggerInferiorRunningRequested:
return "DebuggerInferiorRunningRequested";
case DebuggerInferiorRunning:
return "DebuggerInferiorRunning";
case DebuggerInferiorStopRequested:
return "DebuggerInferiorStopRequested";
case DebuggerInferiorStopped:
return "DebuggerInferiorStopped";
}
return "<unknown>";
}
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
///////////////////////////////////////////////////////////////////////
//
// 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;
static IDebuggerEngine *tcfEngine = 0;
// The creation functions take a list of options pages they can add to.
// This allows for having a "enabled" toggle on the page indepently
// of the engine.
IDebuggerEngine *createGdbEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *);
IDebuggerEngine *createWinEngine(DebuggerManager *, bool /* cmdLineDisabled */, QList<Core::IOptionsPage*> *)
#ifdef CDB_ENABLED
;
#else
{ return 0; }
#endif
IDebuggerEngine *createScriptEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *);
IDebuggerEngine *createTcfEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *);
DebuggerManager::DebuggerManager()
init();
#define doDelete(ptr) delete ptr; ptr = 0
doDelete(gdbEngine);
doDelete(winEngine);
doDelete(scriptEngine);
doDelete(tcfEngine);
#undef doDelete
void DebuggerManager::init()
{
m_status = -1;
m_busy = false;
m_attachedPID = 0;
m_runControl = 0;
m_disassemblerHandler = 0;
m_modulesHandler = 0;
m_registerHandler = 0;
m_statusLabel = new QLabel;
// FIXME: Do something to show overly long messages at least partially
//QSizePolicy policy = m_statusLabel->sizePolicy();
//policy.setHorizontalPolicy(QSizePolicy::MinimumExpanding);
//m_statusLabel->setSizePolicy(policy);
//m_statusLabel->setWordWrap(true);
m_breakWindow = new BreakWindow;
m_disassemblerWindow = new DisassemblerWindow;
m_modulesWindow = new ModulesWindow(this);
m_outputWindow = new DebuggerOutputWindow;
m_registerWindow = new RegisterWindow;
m_stackWindow = new StackWindow;
m_sourceFilesWindow = new SourceFilesWindow;
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);
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)));
connect(theDebuggerAction(ExpandStack), SIGNAL(triggered()),
this, SLOT(reloadFullStack()));
connect(theDebuggerAction(MaximalStackDepth), SIGNAL(triggered()),
this, SLOT(reloadFullStack()));
// 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());
connect(m_disassemblerWindow, SIGNAL(reloadDisassemblerRequested()),
this, SLOT(reloadDisassembler()));
// 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)),
connect(breakView, SIGNAL(breakpointSynchronizationRequested()),
this, SLOT(attemptBreakpointSynchronization()));
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()));
connect(modulesView, SIGNAL(fileOpenRequested(QString)),
this, SLOT(fileOpen(QString)));
connect(modulesView, SIGNAL(newDockRequested(QWidget*)),
this, SLOT(createNewDock(QWidget*)));
// 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()));
connect(sourceFilesView, SIGNAL(fileOpenRequested(QString)),
this, SLOT(fileOpen(QString)));
// Registers
QAbstractItemView *registerView =
qobject_cast<QAbstractItemView *>(m_registerWindow);
m_registerHandler = new RegisterHandler;
registerView->setModel(m_registerHandler->model());
// Locals
QTreeView *localsView = qobject_cast<QTreeView *>(m_localsWindow);
localsView->setModel(m_watchHandler->model());
// Watchers
QTreeView *watchersView = qobject_cast<QTreeView *>(m_watchersWindow);
watchersView->setModel(m_watchHandler->model());
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(theDebuggerAction(AssignValue), SIGNAL(triggered()),
this, SLOT(assignValueInDebugger()), Qt::QueuedConnection);
// Tooltip
QTreeView *tooltipView = qobject_cast<QTreeView *>(m_tooltipWindow);
tooltipView->setModel(m_watchHandler->model());
connect(m_watchHandler, SIGNAL(watchModelUpdateRequested()),
this, SLOT(updateWatchModel()));
m_continueAction = new QAction(this);
m_continueAction->setText(tr("Continue"));
m_continueAction->setIcon(QIcon(":/debugger/images/debugger_continue_small.png"));
m_stopAction = new QAction(this);
m_stopAction->setText(tr("Interrupt"));
m_stopAction->setIcon(QIcon(":/debugger/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(":/debugger/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(":/debugger/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(":/debugger/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(":/debugger/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(":/debugger/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\""));
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
m_watchAction = new QAction(this);
m_watchAction->setText(tr("Add to Watch Window"));
// For usuage hints oin focus{In,Out}
connect(m_continueAction, SIGNAL(triggered()),
this, SLOT(continueExec()));
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()));
connect(theDebuggerAction(ExecuteCommand), SIGNAL(triggered()),
this, SLOT(executeDebuggerCommand()));
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);
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);
}
QList<Core::IOptionsPage*> DebuggerManager::initializeEngines(const QStringList &arguments)
{
QList<Core::IOptionsPage*> rc;
gdbEngine = createGdbEngine(this, &rc);
const bool cdbDisabled = arguments.contains(_("-disable-cdb"));
winEngine = createWinEngine(this, cdbDisabled, &rc);
scriptEngine = createScriptEngine(this, &rc);
tcfEngine = createTcfEngine(this, &rc);
qDebug() << Q_FUNC_INFO << gdbEngine << winEngine << scriptEngine << rc.size();
return rc;
}
IDebuggerEngine *DebuggerManager::engine()
{
return m_engine;
}
IDebuggerManagerAccessForEngines *DebuggerManager::engineInterface()
{
return dynamic_cast<IDebuggerManagerAccessForEngines *>(this);
}
void DebuggerManager::createNewDock(QWidget *widget)
{
QDockWidget *dockWidget = new QDockWidget(widget->windowTitle(), m_mainWindow);
dockWidget->setObjectName(widget->windowTitle());
dockWidget->setFeatures(QDockWidget::DockWidgetClosable);
dockWidget->setWidget(widget);
m_mainWindow->addDockWidget(Qt::TopDockWidgetArea, dockWidget);
dockWidget->show();
}
QDockWidget *DebuggerManager::createDockForWidget(QWidget *widget)
{
QDockWidget *dockWidget = new QDockWidget(widget->windowTitle(), m_mainWindow);
dockWidget->setObjectName(widget->windowTitle());
dockWidget->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable);
dockWidget->setTitleBarWidget(new QWidget(dockWidget));
dockWidget->setWidget(widget);
connect(dockWidget->toggleViewAction(), SIGNAL(triggered()),
this, SLOT(dockActionTriggered()), Qt::QueuedConnection);
m_dockWidgetActiveState.append(false);
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);
// They following views are rarely used in ordinary debugging. Hiding them
// saves cycles since the corresponding information won't be retrieved.
m_sourceFilesDock->hide();
m_registerDock->hide();
m_disassemblerDock->hide();
m_modulesDock->hide();
m_outputDock->hide();
}
void DebuggerManager::updateDockWidgetActiveStates()
{
for (int i = 0; i < m_dockWidgets.size(); ++i) {
m_dockWidgetActiveState[i] = m_dockWidgets.at(i)->isVisible();
}
}
void DebuggerManager::setFloatingDockWidgetsVisible(bool visible)
{
for (int i = 0; i < m_dockWidgets.size(); ++i) {
QDockWidget *dockWidget = m_dockWidgets.at(i);
if (dockWidget->isFloating() && m_dockWidgetActiveState.at(i)) {
dockWidget->setVisible(visible);
}
}
if (visible)
updateDockWidgetActiveStates(); // we can't do that earlier, because the dock widgets are not visible at startup
}
void DebuggerManager::setLocked(bool locked)
{
const QDockWidget::DockWidgetFeatures features =
(locked) ? QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable :
QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable;
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::dockActionTriggered()
{
QDockWidget *dw = qobject_cast<QDockWidget *>(sender()->parent());
if (dw) {
if (dw->isVisible())
dw->raise();
int index = m_dockWidgets.indexOf(dw);
if (index >= 0)
m_dockWidgetActiveState[index] = dw->isVisible();
}
}
QAbstractItemModel *DebuggerManager::threadsModel()
{
return qobject_cast<ThreadsWindow*>(m_threadsWindow)->model();
}
void DebuggerManager::clearStatusMessage()
{
m_statusLabel->setText(m_lastPermanentStatusMessage);
}
void DebuggerManager::showStatusMessage(const QString &msg, int timeout)
{
Q_UNUSED(timeout)
if (Debugger::Constants::Internal::debug)
qDebug() << "STATUS MSG: " << msg;
m_statusLabel->setText(" " + msg);
if (timeout > 0) {
m_statusTimer->setSingleShot(true);
m_statusTimer->start(timeout);
} else {
m_lastPermanentStatusMessage = msg;
m_statusTimer->stop();
}
void DebuggerManager::notifyInferiorStopRequested()
{
setStatus(DebuggerInferiorStopRequested);
showStatusMessage(tr("Stop requested..."), 5000);
}
void DebuggerManager::notifyInferiorStopped()
{
resetLocation();
setStatus(DebuggerInferiorStopped);
showStatusMessage(tr("Stopped."), 5000);
}
void DebuggerManager::notifyInferiorRunningRequested()
{
setStatus(DebuggerInferiorRunningRequested);
showStatusMessage(tr("Running requested..."), 5000);
}
void DebuggerManager::notifyInferiorRunning()
{
setStatus(DebuggerInferiorRunning);
showStatusMessage(tr("Running..."), 5000);
}
void DebuggerManager::notifyInferiorExited()
{
showStatusMessage(tr("Stopped."), 5000);
}
void DebuggerManager::notifyInferiorPidChanged(int pid)
{
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << pid;
//QMessageBox::warning(0, "PID", "PID: " + QString::number(pid));
emit inferiorPidChanged(pid);
}
void DebuggerManager::showApplicationOutput(const QString &str)
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << m_engine;
if (m_engine)
m_engine->shutdown();
m_engine = 0;
#define doDelete(ptr) delete ptr; ptr = 0
doDelete(scriptEngine);
doDelete(gdbEngine);
doDelete(winEngine);
doDelete(tcfEngine);
// Delete these manually before deleting the manager
// (who will delete the models for most views)
doDelete(m_breakWindow);
doDelete(m_disassemblerWindow);
doDelete(m_modulesWindow);
doDelete(m_outputWindow);
doDelete(m_registerWindow);
doDelete(m_stackWindow);
doDelete(m_sourceFilesWindow);
doDelete(m_threadsWindow);
doDelete(m_tooltipWindow);
doDelete(m_watchersWindow);
doDelete(m_localsWindow);
doDelete(m_breakHandler);
doDelete(m_disassemblerHandler);
doDelete(m_threadsHandler);
doDelete(m_modulesHandler);
doDelete(m_registerHandler);
doDelete(m_stackHandler);
doDelete(m_watchHandler);
#undef doDelete
BreakpointData *DebuggerManager::findBreakpoint(const QString &fileName, int lineNumber)
{
if (!m_breakHandler)
return 0;
int index = m_breakHandler->findBreakpoint(fileName, lineNumber);
return index == -1 ? 0 : m_breakHandler->at(index);
}
void DebuggerManager::toggleBreakpoint()
{
QString fileName;
int lineNumber = -1;
queryCurrentTextEditor(&fileName, &lineNumber, 0);
if (lineNumber == -1)
return;
toggleBreakpoint(fileName, lineNumber);
}
void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber)
{
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << fileName << lineNumber;
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;
}
int index = m_breakHandler->findBreakpoint(fileName, lineNumber);
m_breakHandler->setBreakpoint(fileName, lineNumber);
m_breakHandler->removeBreakpoint(index);
void DebuggerManager::toggleBreakpointEnabled(const QString &fileName, int lineNumber)
{
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO << fileName << lineNumber;
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;
}
m_breakHandler->toggleBreakpointEnabled(fileName, lineNumber);
void DebuggerManager::attemptBreakpointSynchronization()
{
if (m_engine)
m_engine->attemptBreakpointSynchronization();
void DebuggerManager::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
m_engine->setToolTipExpression(mousePos, editor, cursorPos);
if (m_engine)
m_engine->updateWatchModel();
}
QVariant DebuggerManager::sessionValue(const QString &name)
{
// this is answered by the plugin
QVariant value;
emit sessionValueRequested(name, &value);
return value;
}
QVariant DebuggerManager::configValue(const QString &name)
{
// this is answered by the plugin
QVariant value;
emit configValueRequested(name, &value);
return value;
}
void DebuggerManager::queryConfigValue(const QString &name, QVariant *value)
{
// this is answered by the plugin
emit configValueRequested(name, value);
}
void DebuggerManager::setConfigValue(const QString &name, const QVariant &value)
{
// this is answered by the plugin
// Figure out the debugger type of an executable
static IDebuggerEngine *determineDebuggerEngine(const QString &executable,
if (executable.endsWith(_(".js")))
return scriptEngine;
#ifndef Q_OS_WIN
Q_UNUSED(errorMessage)
return gdbEngine;
#else
// If a file has PDB files, it has been compiled by VS.
QStringList pdbFiles;
if (!getPDBFiles(executable, &pdbFiles, errorMessage))
if (pdbFiles.empty())
return gdbEngine;
// We need the CDB debugger in order to be able to debug VS
// executables
if (!winEngine) {
*errorMessage = DebuggerManager::tr("Debugging VS executables is not supported.");
return winEngine;
static IDebuggerEngine *determineDebuggerEngine(int /* pid */,
QString * /*errorMessage*/)
{
#ifdef Q_OS_WIN
// Preferably Windows debugger
return winEngine ? winEngine : gdbEngine;
return gdbEngine;
void DebuggerManager::startNewDebugger(DebuggerRunControl *runControl)
m_runControl = runControl;
qDebug() << Q_FUNC_INFO << startMode();
switch (startMode()) {
case StartExternal: {
configValue(_("LastExternalExecutableFile")).toString());
configValue(_("LastExternalExecutableArguments")).toString());
if (dlg.exec() != QDialog::Accepted) {
runControl->debuggingFinished();
return;
}
setConfigValue(_("LastExternalExecutableFile"),
setConfigValue(_("LastExternalExecutableArguments"),
dlg.executableArguments());
m_executable = dlg.executableFile();
m_processArgs = dlg.executableArguments().split(' ');
m_workingDir = QString();
m_attachedPID = -1;
AttachExternalDialog dlg(mainWindow());
if (dlg.exec() != QDialog::Accepted) {
runControl->debuggingFinished();
return;
}
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"));
runControl->debuggingFinished();
return;
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) {
runControl->debuggingFinished();
return;
}
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(_(" "));
configValue(_("LastExternalExecutableFile")).toString());
configValue(_("LastExternalCoreFile")).toString());
if (dlg.exec() != QDialog::Accepted) {
runControl->debuggingFinished();
return;
}
setConfigValue(_("LastExternalExecutableFile"),
setConfigValue(_("LastExternalCoreFile"),
m_executable = dlg.executableFile();
m_coreFile = dlg.coreFile();
m_processArgs.clear();
m_workingDir = QString();
m_attachedPID = -1;
case StartRemote: {
StartRemoteDialog dlg(mainWindow());
QStringList arches;
arches.append(_("i386:x86-64:intel"));
dlg.setRemoteArchitectures(arches);
dlg.setRemoteChannel(
configValue(_("LastRemoteChannel")).toString());
dlg.setRemoteArchitecture(
configValue(_("LastRemoteArchitecture")).toString());
dlg.setServerStartScript(
configValue(_("LastServerStartScript")).toString());
dlg.setUseServerStartScript(
configValue(_("LastUseServerStartScript")).toBool());
if (dlg.exec() != QDialog::Accepted) {
runControl->debuggingFinished();
return;
}
setConfigValue(_("LastRemoteChannel"), dlg.remoteChannel());
setConfigValue(_("LastRemoteArchitecture"), dlg.remoteArchitecture());
setConfigValue(_("LastServerStartScript"), dlg.serverStartScript());
setConfigValue(_("LastUseServerStartScript"), dlg.useServerStartScript());
m_remoteChannel = dlg.remoteChannel();
m_remoteArchitecture = dlg.remoteArchitecture();
m_serverStartScript = dlg.serverStartScript();
if (!dlg.useServerStartScript())
m_serverStartScript.clear();
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
case AttachTcf: {
AttachTcfDialog dlg(mainWindow());
QStringList arches;
arches.append(_("i386:x86-64:intel"));
dlg.setRemoteArchitectures(arches);
dlg.setRemoteChannel(
configValue(_("LastTcfRemoteChannel")).toString());
dlg.setRemoteArchitecture(
configValue(_("LastTcfRemoteArchitecture")).toString());
dlg.setServerStartScript(
configValue(_("LastTcfServerStartScript")).toString());
dlg.setUseServerStartScript(
configValue(_("LastTcfUseServerStartScript")).toBool());
if (dlg.exec() != QDialog::Accepted) {
runControl->debuggingFinished();
return;
}
setConfigValue(_("LastTcfRemoteChannel"), dlg.remoteChannel());
setConfigValue(_("LastTcfRemoteArchitecture"), dlg.remoteArchitecture());
setConfigValue(_("LastTcfServerStartScript"), dlg.serverStartScript());
setConfigValue(_("LastTcfUseServerStartScript"), dlg.useServerStartScript());
m_remoteChannel = dlg.remoteChannel();
m_remoteArchitecture = dlg.remoteArchitecture();
m_serverStartScript = dlg.serverStartScript();
if (!dlg.useServerStartScript())
m_serverStartScript.clear();
break;
}
if (startMode() == AttachExternal)
m_engine = determineDebuggerEngine(m_attachedPID, &errorMessage);
else if (startMode() == AttachTcf)
m_engine = tcfEngine;
m_engine = determineDebuggerEngine(m_executable, &errorMessage);
if (!m_engine) {
QMessageBox::warning(mainWindow(), tr("Warning"),
tr("Cannot debug '%1': %2").arg(m_executable, errorMessage));
debuggingFinished();
return;
qDebug() << m_executable << m_engine;
setBusyCursor(false);
setStatus(DebuggerProcessStartingUp);
if (!m_engine->startDebugger()) {