Newer
Older
/**************************************************************************
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
**************************************************************************/
#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 "disassemblerhandler.h"
#include "breakhandler.h"
#include "moduleshandler.h"
#include "registerhandler.h"
#include "stackhandler.h"
#include "watchhandler.h"
#include <coreplugin/icore.h>
#include <utils/fancymainwindow.h>
#include <projectexplorer/toolchain.h>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QTimer>
#include <QtGui/QApplication>
#include <QtGui/QAction>
#include <QtGui/QComboBox>
#include <QtGui/QDockWidget>
#include <QtGui/QErrorMessage>
#include <QtGui/QFileDialog>
#include <QtGui/QLabel>
#include <QtGui/QMessageBox>
#include <QtGui/QPlainTextEdit>
#include <QtGui/QPushButton>
#include <QtGui/QStatusBar>
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
#include <QtGui/QToolButton>
#include <QtGui/QToolTip>
// 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.
using namespace Debugger::Internal;
IDebuggerEngine *createGdbEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *);
IDebuggerEngine *createWinEngine(DebuggerManager *, bool /* cmdLineEnabled */, QList<Core::IOptionsPage*> *)
#ifdef CDB_ENABLED
;
#else
{ return 0; }
#endif
IDebuggerEngine *createScriptEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *);
IDebuggerEngine *createTcfEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *);
namespace Debugger {
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
<< " serverStartScript=" << p.serverStartScript
<< " toolchain=" << p.toolChainType << '\n';
return str;
}
using namespace Constants;
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>";
}
///////////////////////////////////////////////////////////////////////
//
// DebuggerStartParameters
//
///////////////////////////////////////////////////////////////////////
DebuggerStartParameters::DebuggerStartParameters()
: attachPID(-1),
useTerminal(false),
toolChainType(ProjectExplorer::ToolChain::UNKNOWN)
void DebuggerStartParameters::clear()
{
executable.clear();
coreFile.clear();
processArgs.clear();
environment.clear();
workingDir.clear();
buildDir.clear();
attachPID = -1;
useTerminal = false;
crashParameter.clear();
remoteChannel.clear();
remoteArchitecture.clear();
serverStartScript.clear();
toolChainType = ProjectExplorer::ToolChain::UNKNOWN;
}
///////////////////////////////////////////////////////////////////////
//
// DebuggerManager
//
///////////////////////////////////////////////////////////////////////
static IDebuggerEngine *gdbEngine = 0;
static IDebuggerEngine *winEngine = 0;
static IDebuggerEngine *scriptEngine = 0;
static IDebuggerEngine *tcfEngine = 0;
DebuggerManager::DebuggerManager()
: m_startParameters(new DebuggerStartParameters),
m_inferiorPid(0)
init();
#define doDelete(ptr) delete ptr; ptr = 0
doDelete(gdbEngine);
doDelete(winEngine);
doDelete(scriptEngine);
doDelete(tcfEngine);
#undef doDelete
void DebuggerManager::init()
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_statusTimer = new QTimer(this);
m_mainWindow = new Core::Utils::FancyMainWindow;
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)));
connect(breakView, SIGNAL(breakByFunctionRequested(QString)),
this, SLOT(breakByFunction(QString)), Qt::QueuedConnection);
connect(breakView, SIGNAL(breakByFunctionMainRequested()),
this, SLOT(breakByFunctionMain()), Qt::QueuedConnection);
// Modules
QAbstractItemView *modulesView =
qobject_cast<QAbstractItemView *>(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
m_watchHandler = new WatchHandler;
QTreeView *localsView = qobject_cast<QTreeView *>(m_localsWindow);
localsView->setModel(m_watchHandler->model(LocalsWatch));
// Watchers
QTreeView *watchersView = qobject_cast<QTreeView *>(m_watchersWindow);
watchersView->setModel(m_watchHandler->model(WatchersWatch));
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);
//QTreeView *tooltipView = qobject_cast<QTreeView *>(m_tooltipWindow);
//tooltipView->setModel(m_watchHandler->model(TooltipsWatch));
connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)),
this, SLOT(updateWatchData(WatchData)));
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_watchAction = new QAction(this);
m_watchAction->setText(tr("Add to Watch Window"));
m_reverseDirectionAction = new QAction(this);
m_reverseDirectionAction->setText(tr("Reverse Direction"));
m_reverseDirectionAction->setCheckable(true);
m_reverseDirectionAction->setChecked(false);
//m_reverseDirectionAction->setIcon(QIcon(":/debugger/images/debugger_stepoverproc_small.png"));
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
// 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_statusTimer, SIGNAL(timeout()),
this, SLOT(clearStatusMessage()));
connect(theDebuggerAction(ExecuteCommand), SIGNAL(triggered()),
this, SLOT(executeDebuggerCommand()));
connect(theDebuggerAction(WatchPoint), SIGNAL(triggered()),
this, SLOT(watchPoint()));
m_breakDock = m_mainWindow->addDockForWidget(m_breakWindow);
m_disassemblerDock = m_mainWindow->addDockForWidget(m_disassemblerWindow);
connect(m_disassemblerDock->toggleViewAction(), SIGNAL(toggled(bool)),
this, SLOT(reloadDisassembler()), Qt::QueuedConnection);
m_modulesDock = m_mainWindow->addDockForWidget(m_modulesWindow);
connect(m_modulesDock->toggleViewAction(), SIGNAL(toggled(bool)),
this, SLOT(reloadModules()), Qt::QueuedConnection);
m_registerDock = m_mainWindow->addDockForWidget(m_registerWindow);
connect(m_registerDock->toggleViewAction(), SIGNAL(toggled(bool)),
this, SLOT(reloadRegisters()), Qt::QueuedConnection);
m_outputDock = m_mainWindow->addDockForWidget(m_outputWindow);
m_stackDock = m_mainWindow->addDockForWidget(m_stackWindow);
m_sourceFilesDock = m_mainWindow->addDockForWidget(m_sourceFilesWindow);
connect(m_sourceFilesDock->toggleViewAction(), SIGNAL(toggled(bool)),
this, SLOT(reloadSourceFiles()), Qt::QueuedConnection);
m_threadsDock = m_mainWindow->addDockForWidget(m_threadsWindow);
QSplitter *localsAndWatchers = new QSplitter(Qt::Vertical, 0);
localsAndWatchers->setWindowTitle(m_localsWindow->windowTitle());
localsAndWatchers->addWidget(m_localsWindow);
localsAndWatchers->addWidget(m_watchersWindow);
//localsAndWatchers->addWidget(m_tooltipWindow);
localsAndWatchers->setStretchFactor(0, 3);
localsAndWatchers->setStretchFactor(1, 1);
localsAndWatchers->setStretchFactor(2, 1);
m_watchDock = m_mainWindow->addDockForWidget(localsAndWatchers);
}
QList<Core::IOptionsPage*> DebuggerManager::initializeEngines(unsigned enabledTypeFlags)
{
QList<Core::IOptionsPage*> rc;
if (enabledTypeFlags & GdbEngineType)
gdbEngine = createGdbEngine(this, &rc);
winEngine = createWinEngine(this, (enabledTypeFlags & CdbEngineType), &rc);
if (enabledTypeFlags & ScriptEngineType)
scriptEngine = createScriptEngine(this, &rc);
if (enabledTypeFlags & TcfEngineType)
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();
}
m_mainWindow->setTrackingEnabled(false);
QList<QDockWidget *> dockWidgets = m_mainWindow->dockWidgets();
foreach (QDockWidget *dockWidget, dockWidgets) {
dockWidget->setFloating(false);
foreach (QDockWidget *dockWidget, 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();
m_mainWindow->setTrackingEnabled(true);
}
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(QLatin1String(" ") + 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()
{
void DebuggerManager::notifyInferiorPidChanged(qint64 pid)
qDebug() << Q_FUNC_INFO << m_inferiorPid << pid;
if (m_inferiorPid != pid) {
m_inferiorPid = 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);
&& status() != DebuggerInferiorStopped
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);
void DebuggerManager::updateWatchData(const WatchData &data)
{
if (m_engine)
m_engine->updateWatchData(data);
}
// this is answered by the plugin
QVariant value;
emit sessionValueRequested(name, &value);
return value;
}
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
static inline QString msgEngineNotAvailable(const char *engine)
{
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::OTHER:
case ProjectExplorer::ToolChain::UNKNOWN:
case ProjectExplorer::ToolChain::INVALID:
break;
}
if (Debugger::Constants::Internal::debug)
qDebug() << "Toolchain" << tc << rc;
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)
if (IDebuggerEngine *tce = debuggerEngineForToolChain(static_cast<ProjectExplorer::ToolChain::ToolChainType>(toolChainType)))
return tce;
if (executable.endsWith(_(".js"))) {
if (!scriptEngine) {
*errorMessage = msgEngineNotAvailable("Script Engine");
return 0;
}
return scriptEngine;
#ifndef Q_OS_WIN
Q_UNUSED(settingsIdHint)
if (!gdbEngine) {
*errorMessage = msgEngineNotAvailable("Gdb Engine");
return 0;
}
return gdbEngine;
#else
// 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 currently not enabled.");
*settingsIdHint = QLatin1String("Cdb");
return winEngine;
static IDebuggerEngine *determineDebuggerEngine(int /* pid */,
int toolChainType,
QString *errorMessage)
if (IDebuggerEngine *tce = debuggerEngineForToolChain(static_cast<ProjectExplorer::ToolChain::ToolChainType>(toolChainType)))
return tce;
#ifdef Q_OS_WIN
// Preferably Windows debugger
if (winEngine)
return winEngine;
if (gdbEngine)
return gdbEngine;
*errorMessage = msgEngineNotAvailable("Gdb Engine");
return 0;
if (!gdbEngine) {
*errorMessage = msgEngineNotAvailable("Gdb Engine");
return 0;
}
return gdbEngine;
void DebuggerManager::startNewDebugger(DebuggerRunControl *runControl,
const QSharedPointer<DebuggerStartParameters> &startParameters)
qDebug() << Q_FUNC_INFO << '\n' << *startParameters;
m_startParameters = startParameters;
m_inferiorPid = startParameters->attachPID > 0 ? startParameters->attachPID : 0;
m_runControl = runControl;
const QString toolChainName = ProjectExplorer::ToolChain::toolChainName(static_cast<ProjectExplorer::ToolChain::ToolChainType>(m_startParameters->toolChainType));
showDebuggerOutput(LogStatus, tr("Starting debugger for tool chain '%1'...").arg(toolChainName));
QString settingsIdHint;
switch (startMode()) {
case AttachExternal:
case AttachCrashedExternal:
m_engine = determineDebuggerEngine(m_startParameters->attachPID, m_startParameters->toolChainType, &errorMessage);
break;
case AttachTcf:
m_engine = tcfEngine;
break;
default:
m_engine = determineDebuggerEngine(m_startParameters->executable, m_startParameters->toolChainType, &errorMessage, &settingsIdHint);
break;
}
if (!m_engine) {
debuggingFinished();
// Create Message box with possibility to go to settings
QAbstractButton *settingsButton = 0;
QMessageBox msgBox(QMessageBox::Warning, tr("Warning"), tr("Cannot debug '%1' (tool chain: '%2'): %3").
arg(m_startParameters->executable, toolChainName, errorMessage), QMessageBox::Ok);
if (!settingsIdHint.isEmpty())
settingsButton = msgBox.addButton(tr("Settings..."), QMessageBox::AcceptRole);
msgBox.exec();
if (msgBox.clickedButton() == settingsButton)
Core::ICore::instance()->showOptionsDialog(_(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY), settingsIdHint);
qDebug() << m_startParameters->executable << m_engine;
setBusyCursor(false);
if (!m_engine->startDebugger(m_startParameters)) {
debuggingFinished();
return;
}
void DebuggerManager::cleanupViews()
{
resetLocation();
breakHandler()->setAllPending();
stackHandler()->removeAll();
threadsHandler()->removeAll();
disassemblerHandler()->removeAll();
modulesHandler()->removeAll();
watchHandler()->cleanup();
m_sourceFilesWindow->removeAll();
if (Debugger::Constants::Internal::debug)
qDebug() << Q_FUNC_INFO;
cleanupViews();
setStatus(DebuggerProcessNotReady);
setBusyCursor(false);
emit debuggingFinished();
}
QSharedPointer<DebuggerStartParameters> DebuggerManager::startParameters() const
{
return m_startParameters;
}
void DebuggerManager::setQtDumperLibraryName(const QString &dl)
{
m_dumperLib = dl;
}
void DebuggerManager::setQtDumperLibraryLocations(const QStringList &dl)
{
m_dumperLibLocations = dl;
}
qint64 DebuggerManager::inferiorPid() const
{
return m_inferiorPid;
}
void DebuggerManager::assignValueInDebugger()
{
if (QAction *action = qobject_cast<QAction *>(sender())) {
QString str = action->data().toString();
int i = str.indexOf('=');
if (i != -1)
assignValueInDebugger(str.left(i), str.mid(i + 1));
void DebuggerManager::assignValueInDebugger(const QString &expr, const QString &value)
{
QTC_ASSERT(m_engine, return);
m_engine->assignValueInDebugger(expr, value);
QTC_ASSERT(m_engine, return);
m_engine->activateFrame(index);
QTC_ASSERT(m_engine, return);
m_engine->selectThread(index);
QTC_ASSERT(m_engine, return);
m_engine->loadAllSymbols();
}
void DebuggerManager::loadSymbols(const QString &module)
{
QTC_ASSERT(m_engine, return);
m_engine->loadSymbols(module);
QList<Symbol> DebuggerManager::moduleSymbols(const QString &moduleName)
{
QTC_ASSERT(m_engine, return QList<Symbol>());
return m_engine->moduleSymbols(moduleName);
}