debuggerengine.cpp 40.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "debuggerengine.h"

#include "debuggeractions.h"
#include "debuggeragents.h"
#include "debuggerrunner.h"
#include "debuggerplugin.h"
#include "debuggerstringutils.h"
37
#include "debuggertooltip.h"
38
#include "logwindow.h"
39 40 41 42 43 44 45 46 47

#include "breakhandler.h"
#include "moduleshandler.h"
#include "registerhandler.h"
#include "snapshothandler.h"
#include "sourcefileshandler.h"
#include "stackhandler.h"
#include "threadshandler.h"
#include "watchhandler.h"
hjk's avatar
hjk committed
48
#include "watchutils.h"
49
#include "breakwindow.h"
50

hjk's avatar
hjk committed
51
#include <coreplugin/icore.h>
52
#include <coreplugin/ifile.h>
53 54
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
hjk's avatar
hjk committed
55

56
#include <projectexplorer/toolchaintype.h>
57 58 59

#include <qt4projectmanager/qt4projectmanagerconstants.h>

hjk's avatar
hjk committed
60 61
#include <texteditor/itexteditor.h>

62
#include <utils/environment.h>
63 64 65 66 67
#include <utils/savedaction.h>
#include <utils/qtcassert.h>

#include <QtCore/QDebug>
#include <QtCore/QTimer>
68
#include <QtCore/QFutureInterface>
69 70 71 72

#include <QtGui/QAbstractItemView>
#include <QtGui/QStandardItemModel>
#include <QtGui/QAction>
73
#include <QtGui/QMenu>
74
#include <QtGui/QMessageBox>
hjk's avatar
hjk committed
75
#include <QtGui/QPlainTextEdit>
76
#include <QtGui/QPushButton>
hjk's avatar
hjk committed
77 78
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
79
#include <QtGui/QTreeWidget>
80
#include <QtGui/QMainWindow>
81

hjk's avatar
hjk committed
82
using namespace Core;
83 84
using namespace Debugger;
using namespace Debugger::Internal;
hjk's avatar
hjk committed
85 86
using namespace ProjectExplorer;
using namespace TextEditor;
87

hjk's avatar
hjk committed
88 89 90 91 92 93 94
//#define DEBUG_STATE 1
#if DEBUG_STATE
#   define SDEBUG(s) qDebug() << s
#else
#   define SDEBUG(s)
#endif
# define XSDEBUG(s) qDebug() << s
95 96 97 98 99 100 101

///////////////////////////////////////////////////////////////////////
//
// DebuggerStartParameters
//
///////////////////////////////////////////////////////////////////////

102
DebuggerStartParameters::DebuggerStartParameters() :
103
    isSnapshot(false),
104 105
    attachPID(-1),
    useTerminal(false),
106 107
    breakAtMain(false),
    qmlServerAddress("127.0.0.1"),
108
    qmlServerPort(0),
hjk's avatar
hjk committed
109
    useServerStartScript(false),
110
    connParams(SshConnectionParameters::NoProxy),
111
    toolChainType(ToolChain_UNKNOWN),
112 113
    startMode(NoStartMode),
    executableUid(0)
114 115 116 117 118 119 120 121 122 123 124 125
{}

void DebuggerStartParameters::clear()
{
    *this = DebuggerStartParameters();
}


namespace Debugger {

QDebug operator<<(QDebug d, DebuggerState state)
{
hjk's avatar
hjk committed
126 127
    //return d << DebuggerEngine::stateName(state) << '(' << int(state) << ')';
    return d << DebuggerEngine::stateName(state);
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
}

QDebug operator<<(QDebug str, const DebuggerStartParameters &sp)
{
    QDebug nospace = str.nospace();
    const QString sep = QString(QLatin1Char(','));
    nospace << "executable=" << sp.executable
            << " coreFile=" << sp.coreFile
            << " processArgs=" << sp.processArgs.join(sep)
            << " environment=<" << sp.environment.size() << " variables>"
            << " workingDir=" << sp.workingDirectory
            << " attachPID=" << sp.attachPID
            << " useTerminal=" << sp.useTerminal
            << " remoteChannel=" << sp.remoteChannel
            << " remoteArchitecture=" << sp.remoteArchitecture
            << " symbolFileName=" << sp.symbolFileName
hjk's avatar
hjk committed
144
            << " useServerStartScript=" << sp.useServerStartScript
145 146 147 148 149 150 151 152 153 154
            << " serverStartScript=" << sp.serverStartScript
            << " toolchain=" << sp.toolChainType << '\n';
    return str;
}

const char *DebuggerEngine::stateName(int s)
{
#    define SN(x) case x: return #x;
    switch (s) {
        SN(DebuggerNotReady)
hjk's avatar
hjk committed
155
        SN(EngineSetupRequested)
156 157
        SN(EngineSetupOk)
        SN(EngineSetupFailed)
hjk's avatar
hjk committed
158 159
        SN(EngineRunFailed)
        SN(InferiorSetupRequested)
hjk's avatar
hjk committed
160
        SN(InferiorSetupFailed)
hjk's avatar
hjk committed
161 162 163 164
        SN(EngineRunRequested)
        SN(InferiorRunRequested)
        SN(InferiorRunOk)
        SN(InferiorRunFailed)
165
        SN(InferiorUnrunnable)
hjk's avatar
hjk committed
166 167
        SN(InferiorStopRequested)
        SN(InferiorStopOk)
168
        SN(InferiorStopFailed)
hjk's avatar
hjk committed
169 170
        SN(InferiorShutdownRequested)
        SN(InferiorShutdownOk)
171
        SN(InferiorShutdownFailed)
hjk's avatar
hjk committed
172 173 174 175
        SN(EngineShutdownRequested)
        SN(EngineShutdownOk)
        SN(EngineShutdownFailed)
        SN(DebuggerFinished)
176 177 178 179 180
    }
    return "<unknown>";
#    undef SN
}

181

182 183 184 185 186 187
//////////////////////////////////////////////////////////////////////
//
// DebuggerEnginePrivate
//
//////////////////////////////////////////////////////////////////////

188
class DebuggerEnginePrivate : public QObject
189
{
190 191
    Q_OBJECT

192 193 194 195
public:
    DebuggerEnginePrivate(DebuggerEngine *engine, const DebuggerStartParameters &sp)
      : m_engine(engine),
        m_runControl(0),
196
        m_isActive(false),
197 198
        m_startParameters(sp),
        m_state(DebuggerNotReady),
hjk's avatar
hjk committed
199
        m_lastGoodState(DebuggerNotReady),
Friedemann Kleint's avatar
Friedemann Kleint committed
200
        m_targetState(DebuggerNotReady),
201
        m_modulesHandler(),
202
        m_registerHandler(),
203 204
        m_sourceFilesHandler(),
        m_stackHandler(),
hjk's avatar
hjk committed
205
        m_threadsHandler(),
206
        m_watchHandler(engine),
207
        m_disassemblerViewAgent(engine),
208
        m_isSlaveEngine(false)
209
    {}
210 211

    ~DebuggerEnginePrivate() {}
212

213 214 215 216
public slots:
    void breakpointSetRemoveMarginActionTriggered();
    void breakpointEnableDisableMarginActionTriggered();

hjk's avatar
hjk committed
217 218
    void doSetupInferior();
    void doRunEngine();
hjk's avatar
hjk committed
219 220
    void doShutdownEngine();
    void doShutdownInferior();
221
    void doInterruptInferior();
hjk's avatar
hjk committed
222
    void doFinishDebugger();
hjk's avatar
hjk committed
223

224 225
    void queueRunEngine()
    {
hjk's avatar
hjk committed
226 227 228 229 230
        m_engine->setState(EngineRunRequested);
        m_engine->showMessage(_("QUEUE: RUN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doRunEngine()));
    }

231 232
    void queueShutdownEngine()
    {
hjk's avatar
hjk committed
233 234 235 236 237
        m_engine->setState(EngineShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doShutdownEngine()));
    }

238 239
    void queueShutdownInferior()
    {
hjk's avatar
hjk committed
240 241 242 243 244
        m_engine->setState(InferiorShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN INFERIOR"));
        QTimer::singleShot(0, this, SLOT(doShutdownInferior()));
    }

245 246
    void queueFinishDebugger()
    {
247 248 249 250
        QTC_ASSERT(state() == EngineShutdownOk
            || state() == EngineShutdownFailed, qDebug() << state());
        m_engine->setState(DebuggerFinished);
        m_engine->showMessage(_("QUEUE: FINISH DEBUGGER"));
hjk's avatar
hjk committed
251 252 253
        QTimer::singleShot(0, this, SLOT(doFinishDebugger()));
    }

254 255
    void raiseApplication()
    {
hjk's avatar
hjk committed
256
        QTC_ASSERT(m_runControl, return);
257 258 259
        m_runControl->bringApplicationToForeground(m_inferiorPid);
    }

260 261
private slots:
    void slotEditBreakpoint();
262 263
    void slotRunToLine();
    void slotJumpToLine();
264

265
public:
hjk's avatar
hjk committed
266 267
    DebuggerState state() const { return m_state; }

268 269
    DebuggerEngine *m_engine; // Not owned.
    DebuggerRunControl *m_runControl;  // Not owned.
270
    bool m_isActive;
271 272

    DebuggerStartParameters m_startParameters;
hjk's avatar
hjk committed
273 274

    // The current state.
275 276
    DebuggerState m_state;

hjk's avatar
hjk committed
277 278 279 280 281 282
    // The state we had before something unexpected happend.
    DebuggerState m_lastGoodState;

    // The state we are aiming for.
    DebuggerState m_targetState;

283 284 285 286 287 288 289 290 291
    qint64 m_inferiorPid;

    ModulesHandler m_modulesHandler;
    RegisterHandler m_registerHandler;
    SourceFilesHandler m_sourceFilesHandler;
    StackHandler m_stackHandler;
    ThreadsHandler m_threadsHandler;
    WatchHandler m_watchHandler;
    DisassemblerViewAgent m_disassemblerViewAgent;
292
    QFutureInterface<void> m_progress;
293

294
    bool m_isSlaveEngine;
295 296
};

297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
// Retrieve file name and line and optionally address
// from the data set on the text editor context menu action.
static bool positionFromContextActionData(const QObject *sender,
                                          QString *fileName,
                                          int *lineNumber,
                                          quint64 *address = 0)
{
    if (const QAction *action = qobject_cast<const QAction *>(sender)) {
        const QVariantList data = action->data().toList();
        if (data.size() >= (address ? 3 : 2)) {
            *fileName = data.front().toString();
            *lineNumber = data.at(1).toInt();
            if (address)
                *address = data.at(2).toULongLong();
            return true;
        }
    }
    return false;
}

317 318
void DebuggerEnginePrivate::breakpointSetRemoveMarginActionTriggered()
{
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
    QString fileName;
    int lineNumber;
    quint64 address;
    if (positionFromContextActionData(sender(), &fileName, &lineNumber, &address))
        m_engine->breakHandler()->toggleBreakpoint(fileName, lineNumber, address);
 }


void DebuggerEnginePrivate::slotRunToLine()
{
    // Run to line, file name and line number set as list.
    QString fileName;
    int lineNumber;
    if (positionFromContextActionData(sender(), &fileName, &lineNumber)) {
        m_engine->resetLocation();
        m_engine->executeRunToLine(fileName, lineNumber);
    }
}

void DebuggerEnginePrivate::slotJumpToLine()
{
    QString fileName;
    int lineNumber;
    if (positionFromContextActionData(sender(), &fileName, &lineNumber))
        m_engine->executeJumpToLine(fileName, lineNumber);
}

 void DebuggerEnginePrivate::breakpointEnableDisableMarginActionTriggered()
{
    QString fileName;
    int lineNumber;
    if (positionFromContextActionData(sender(), &fileName, &lineNumber))
        m_engine->breakHandler()->toggleBreakpointEnabled(fileName, lineNumber);
352 353
}

354 355 356 357 358 359 360
void DebuggerEnginePrivate::slotEditBreakpoint()
{
    const QAction *act = qobject_cast<QAction *>(sender());
    QTC_ASSERT(act, return);
    const QVariant data = act->data();
    QTC_ASSERT(qVariantCanConvert<BreakpointData *>(data), return);
    BreakpointData *breakPointData = qvariant_cast<BreakpointData *>(data);
Arvid Ephraim Picciani's avatar
Arvid Ephraim Picciani committed
361
    BreakWindow::editBreakpoint(breakPointData, ICore::instance()->mainWindow());
362 363
}

364 365 366 367 368 369 370 371 372 373 374 375 376 377

//////////////////////////////////////////////////////////////////////
//
// DebuggerEngine
//
//////////////////////////////////////////////////////////////////////

DebuggerEngine::DebuggerEngine(const DebuggerStartParameters &startParameters)
  : d(new DebuggerEnginePrivate(this, startParameters))
{
}

DebuggerEngine::~DebuggerEngine()
{
378 379
    disconnect();
    delete d;
380 381
}

382
void DebuggerEngine::showStatusMessage(const QString &msg, int timeout) const
383
{
384
    showMessage(msg, StatusBar, timeout);
385
}
386

387 388 389 390 391 392
void DebuggerEngine::removeTooltip()
{
    watchHandler()->removeTooltip();
    hideDebuggerToolTip();
}

393 394 395 396 397 398 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 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
void DebuggerEngine::showModuleSymbols
    (const QString &moduleName, const Symbols &symbols)
{
    QTreeWidget *w = new QTreeWidget;
    w->setColumnCount(3);
    w->setRootIsDecorated(false);
    w->setAlternatingRowColors(true);
    w->setSortingEnabled(true);
    w->setHeaderLabels(QStringList() << tr("Symbol") << tr("Address") << tr("Code"));
    w->setWindowTitle(tr("Symbols in \"%1\"").arg(moduleName));
    foreach (const Symbol &s, symbols) {
        QTreeWidgetItem *it = new QTreeWidgetItem;
        it->setData(0, Qt::DisplayRole, s.name);
        it->setData(1, Qt::DisplayRole, s.address);
        it->setData(2, Qt::DisplayRole, s.state);
        w->addTopLevelItem(it);
    }
    plugin()->createNewDock(w);
}

void DebuggerEngine::frameUp()
{
    int currentIndex = stackHandler()->currentIndex();
    activateFrame(qMin(currentIndex + 1, stackHandler()->stackSize() - 1));
}

void DebuggerEngine::frameDown()
{
    int currentIndex = stackHandler()->currentIndex();
    activateFrame(qMax(currentIndex - 1, 0));
}

ModulesHandler *DebuggerEngine::modulesHandler() const
{
    return &d->m_modulesHandler;
}

RegisterHandler *DebuggerEngine::registerHandler() const
{
    return &d->m_registerHandler;
}

StackHandler *DebuggerEngine::stackHandler() const
{
    return &d->m_stackHandler;
}

ThreadsHandler *DebuggerEngine::threadsHandler() const
{
    return &d->m_threadsHandler;
}

WatchHandler *DebuggerEngine::watchHandler() const
{
    return &d->m_watchHandler;
}

450 451 452 453
//SnapshotHandler *DebuggerEngine::snapshotHandler() const
//{
//    return &d->m_snapshotHandler;
//}
454 455 456 457 458 459 460 461

SourceFilesHandler *DebuggerEngine::sourceFilesHandler() const
{
    return &d->m_sourceFilesHandler;
}

QAbstractItemModel *DebuggerEngine::modulesModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
462 463 464 465
    QAbstractItemModel *model = d->m_modulesHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ModulesModel"));
    return model;
466 467 468 469
}

QAbstractItemModel *DebuggerEngine::registerModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
470 471 472 473
    QAbstractItemModel *model = d->m_registerHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("RegisterModel"));
    return model;
474 475 476 477
}

QAbstractItemModel *DebuggerEngine::stackModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
478 479 480 481
    QAbstractItemModel *model = d->m_stackHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("StackModel"));
    return model;
482 483 484 485
}

QAbstractItemModel *DebuggerEngine::threadsModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
486 487 488 489
    QAbstractItemModel *model = d->m_threadsHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ThreadsModel"));
    return model;
490 491 492 493
}

QAbstractItemModel *DebuggerEngine::localsModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
494 495 496 497
    QAbstractItemModel *model = d->m_watchHandler.model(LocalsWatch);
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("LocalsModel"));
    return model;
498 499 500 501
}

QAbstractItemModel *DebuggerEngine::watchersModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
502 503 504 505
    QAbstractItemModel *model = d->m_watchHandler.model(WatchersWatch);
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("WatchersModel"));
    return model;
506 507 508 509
}

QAbstractItemModel *DebuggerEngine::returnModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
510 511 512 513
    QAbstractItemModel *model = d->m_watchHandler.model(ReturnWatch);
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ReturnModel"));
    return model;
514 515 516 517
}

QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
518 519 520 521
    QAbstractItemModel *model = d->m_sourceFilesHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("SourceFilesModel"));
    return model;
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
}

void DebuggerEngine::fetchMemory(MemoryViewAgent *, QObject *,
        quint64 addr, quint64 length)
{
    Q_UNUSED(addr);
    Q_UNUSED(length);
}

void DebuggerEngine::setRegisterValue(int regnr, const QString &value)
{
    Q_UNUSED(regnr);
    Q_UNUSED(value);
}

void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) const
{
539 540
    //if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
    //    qDebug() << qPrintable(msg) << "IN STATE" << state();
541
    plugin()->showMessage(msg, channel, timeout);
542 543 544 545 546
    if (d->m_runControl) {
        d->m_runControl->showMessage(msg, channel);
    } else {
        qWarning("Warning: %s (no active run control)", qPrintable(msg));
    }
547 548 549 550
}

void DebuggerEngine::startDebugger(DebuggerRunControl *runControl)
{
hjk's avatar
hjk committed
551
    if (!isSlaveEngine()) {
552
        d->m_progress.setProgressRange(0, 1000);
553 554 555
        Core::FutureProgress *fp = Core::ICore::instance()->progressManager()
            ->addTask(d->m_progress.future(),
            tr("Launching"), _("Debugger.Launcher"));
556
        fp->setKeepOnFinish(Core::FutureProgress::DontKeepOnFinish);
557 558
        d->m_progress.reportStarted();
    }
559 560
    QTC_ASSERT(runControl, notifyEngineSetupFailed(); return);
    QTC_ASSERT(!d->m_runControl, notifyEngineSetupFailed(); return);
561 562 563 564 565 566 567

    d->m_runControl = runControl;

    d->m_inferiorPid = d->m_startParameters.attachPID > 0
        ? d->m_startParameters.attachPID : 0;

    if (d->m_startParameters.environment.empty())
568
        d->m_startParameters.environment = Utils::Environment().toStringList();
569 570 571 572 573 574 575 576

    if (d->m_startParameters.breakAtMain)
        breakByFunctionMain();

    const unsigned engineCapabilities = debuggerCapabilities();
    theDebuggerAction(OperateByInstruction)
        ->setEnabled(engineCapabilities & DisassemblerCapability);

577 578
    QTC_ASSERT(state() == DebuggerNotReady || state() == DebuggerFinished,
         qDebug() << state());
hjk's avatar
hjk committed
579
    setState(EngineSetupRequested);
580

581
    d->m_progress.setProgressValue(200);
hjk's avatar
hjk committed
582
    setupEngine();
583 584 585 586 587 588 589 590 591 592 593 594 595 596
}

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

void DebuggerEngine::breakByFunction(const QString &functionName)
{
597 598
    breakHandler()->breakByFunction(functionName);
    breakHandler()->synchronizeBreakpoints();
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
}

void DebuggerEngine::resetLocation()
{
    d->m_disassemblerViewAgent.resetLocation();
    d->m_stackHandler.setCurrentIndex(-1);
    plugin()->resetLocation();
}

void DebuggerEngine::gotoLocation(const QString &fileName, int lineNumber, bool setMarker)
{
    StackFrame frame;
    frame.file = fileName;
    frame.line = lineNumber;
    gotoLocation(frame, setMarker);
}

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


hjk's avatar
hjk committed
628
void DebuggerEngine::executeRunToLine()
629
{
630 631 632 633 634 635
    QString fileName;
    int lineNumber;
    if (currentTextEditorPosition(&fileName, &lineNumber)) {
        resetLocation();
        executeRunToLine(fileName, lineNumber);
    }
636 637
}

hjk's avatar
hjk committed
638
void DebuggerEngine::executeRunToFunction()
639
{
hjk's avatar
hjk committed
640
    ITextEditor *textEditor = currentTextEditor();
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
    QTC_ASSERT(textEditor, return);
    QPlainTextEdit *ed = qobject_cast<QPlainTextEdit*>(textEditor->widget());
    if (!ed)
        return;
    QTextCursor cursor = ed->textCursor();
    QString functionName = cursor.selectedText();
    if (functionName.isEmpty()) {
        const QTextBlock block = cursor.block();
        const QString line = block.text();
        foreach (const QString &str, line.trimmed().split('(')) {
            QString a;
            for (int i = str.size(); --i >= 0; ) {
                if (!str.at(i).isLetterOrNumber())
                    break;
                a = str.at(i) + a;
            }
            if (!a.isEmpty()) {
                functionName = a;
                break;
            }
        }
    }

hjk's avatar
hjk committed
664 665 666 667
    if (functionName.isEmpty())
        return;
    resetLocation();
    executeRunToFunction(functionName);
668 669
}

hjk's avatar
hjk committed
670
void DebuggerEngine::executeJumpToLine()
671
{
672 673 674 675
    QString fileName;
    int lineNumber;
    if (currentTextEditorPosition(&fileName, &lineNumber))
        executeJumpToLine(fileName, lineNumber);
676 677
}

678 679 680
// Called from RunControl.
void DebuggerEngine::handleStartFailed()
{
681
    showMessage("HANDLE RUNCONTROL START FAILED");
682
    d->m_runControl = 0;
683
    d->m_progress.setProgressValue(900);
684 685
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
686 687
}

688 689
// Called from RunControl.
void DebuggerEngine::handleFinished()
690
{
691
    showMessage("HANDLE RUNCONTROL FINISHED");
692
    d->m_runControl = 0;
693 694 695 696
    modulesHandler()->removeAll();
    stackHandler()->removeAll();
    threadsHandler()->removeAll();
    watchHandler()->cleanup();
697
    d->m_progress.setProgressValue(1000);
698
    d->m_progress.reportFinished();
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
}

const DebuggerStartParameters &DebuggerEngine::startParameters() const
{
    return d->m_startParameters;
}

DebuggerStartParameters &DebuggerEngine::startParameters()
{
    return d->m_startParameters;
}


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

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

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

void DebuggerEngine::showQtDumperLibraryWarning(const QString &details)
{
740
    QMessageBox dialog(plugin()->mainWindow());
Leena Miettinen's avatar
Leena Miettinen committed
741
    QPushButton *qtPref = dialog.addButton(tr("Open Qt4 Options"),
742
        QMessageBox::ActionRole);
Leena Miettinen's avatar
Leena Miettinen committed
743
    QPushButton *helperOff = dialog.addButton(tr("Turn off Helper Usage"),
744
        QMessageBox::ActionRole);
Leena Miettinen's avatar
Leena Miettinen committed
745
    QPushButton *justContinue = dialog.addButton(tr("Continue Anyway"),
746 747
        QMessageBox::AcceptRole);
    dialog.setDefaultButton(justContinue);
Leena Miettinen's avatar
Leena Miettinen committed
748
    dialog.setWindowTitle(tr("Debugging Helper Missing"));
749 750 751 752 753
    dialog.setText(tr("The debugger could not load the debugging helper library."));
    dialog.setInformativeText(tr(
        "The debugging helper is used to nicely format the values of some Qt "
        "and Standard Library data types. "
        "It must be compiled for each used Qt version separately. "
Leena Miettinen's avatar
Leena Miettinen committed
754 755
        "On the Qt4 options page, select a Qt installation "
        "and click Rebuild."));
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
    if (!details.isEmpty())
        dialog.setDetailedText(details);
    dialog.exec();
    if (dialog.clickedButton() == qtPref) {
        Core::ICore::instance()->showOptionsDialog(
            _(Qt4ProjectManager::Constants::QT_SETTINGS_CATEGORY),
            _(Qt4ProjectManager::Constants::QTVERSION_SETTINGS_PAGE_ID));
    } else if (dialog.clickedButton() == helperOff) {
        theDebuggerAction(UseDebuggingHelpers)
            ->setValue(qVariantFromValue(false), false);
    }
}

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

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

hjk's avatar
hjk committed
781
DebuggerState DebuggerEngine::lastGoodState() const
782
{
hjk's avatar
hjk committed
783 784 785 786 787 788 789
    return d->m_lastGoodState;
}

DebuggerState DebuggerEngine::targetState() const
{
    return d->m_targetState;
}
790

hjk's avatar
hjk committed
791 792 793
static bool isAllowedTransition(DebuggerState from, DebuggerState to)
{
    switch (from) {
794
    case DebuggerNotReady:
795
        return to == EngineSetupRequested;
796

hjk's avatar
hjk committed
797
    case EngineSetupRequested:
798 799
        return to == EngineSetupOk || to == EngineSetupFailed;
    case EngineSetupFailed:
800
        // FIXME: In therory it's the engine's task to go into a
801 802 803
        // proper "Shutdown" state before calling notifyEngineSetupFailed
        //return to == DebuggerFinished;
        return to == EngineShutdownRequested;
804
    case EngineSetupOk:
hjk's avatar
hjk committed
805
        return to == InferiorSetupRequested || to == EngineShutdownRequested;
806

hjk's avatar
hjk committed
807 808
    case InferiorSetupRequested:
        return to == EngineRunRequested || to == InferiorSetupFailed;
hjk's avatar
hjk committed
809
    case InferiorSetupFailed:
hjk's avatar
hjk committed
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
        return to == EngineShutdownRequested;

    case EngineRunRequested:
        return to == InferiorRunRequested || to == InferiorStopRequested
            || to == InferiorUnrunnable || to == EngineRunFailed;

    case EngineRunFailed:
        return to == InferiorShutdownRequested;

    case InferiorRunRequested:
        return to == InferiorRunOk || to == InferiorRunFailed;
    case InferiorRunFailed:
        return to == InferiorStopOk;
    case InferiorRunOk:
        return to == InferiorStopRequested || to == InferiorStopOk;

    case InferiorStopRequested:
        return to == InferiorStopOk || to == InferiorStopFailed;
    case InferiorStopOk:
        return to == InferiorRunRequested || to == InferiorShutdownRequested
            || to == InferiorStopOk;
831
    case InferiorStopFailed:
hjk's avatar
hjk committed
832
        return to == EngineShutdownRequested;
833 834

    case InferiorUnrunnable:
hjk's avatar
hjk committed
835 836 837 838 839
        return to == InferiorShutdownRequested;
    case InferiorShutdownRequested:
        return to == InferiorShutdownOk || to == InferiorShutdownFailed;
    case InferiorShutdownOk:
        return to == EngineShutdownRequested;
840
    case InferiorShutdownFailed:
hjk's avatar
hjk committed
841
        return to == EngineShutdownRequested;
842

hjk's avatar
hjk committed
843
    case EngineShutdownRequested:
844
        return to == EngineShutdownOk || to == EngineShutdownFailed;
hjk's avatar
hjk committed
845 846 847 848 849 850
    case EngineShutdownOk:
        return to == DebuggerFinished;
    case EngineShutdownFailed:
        return to == DebuggerFinished;

    case DebuggerFinished:
851
        return to == EngineSetupRequested; // Happens on restart.
852 853 854 855 856 857
    }

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

858
void DebuggerEngine::notifyEngineSetupFailed()
hjk's avatar
hjk committed
859
{
hjk's avatar
hjk committed
860
    showMessage(_("NOTE: ENGINE SETUP FAILED"));
hjk's avatar
hjk committed
861
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
862
    setState(EngineSetupFailed);
hjk's avatar
hjk committed
863 864
    QTC_ASSERT(d->m_runControl, return);
    d->m_runControl->startFailed();
hjk's avatar
hjk committed
865
    setState(DebuggerFinished);
hjk's avatar
hjk committed
866 867
}

868
void DebuggerEngine::notifyEngineSetupOk()
869
{
hjk's avatar
hjk committed
870
    showMessage(_("NOTE: ENGINE SETUP OK"));
hjk's avatar
hjk committed
871
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
872
    setState(EngineSetupOk);
hjk's avatar
hjk committed
873
    QTC_ASSERT(d->m_runControl, return);
hjk's avatar
hjk committed
874
    showMessage(_("QUEUE: SETUP INFERIOR"));
hjk's avatar
hjk committed
875
    QTimer::singleShot(0, d, SLOT(doSetupInferior()));
876 877
}

hjk's avatar
hjk committed
878
void DebuggerEnginePrivate::doSetupInferior()
879
{
880
    m_engine->showMessage(_("CALL: SETUP INFERIOR"));
hjk's avatar
hjk committed
881
    QTC_ASSERT(state() == EngineSetupOk, qDebug() << state());
882
    m_progress.setProgressValue(250);
hjk's avatar
hjk committed
883
    m_engine->setState(InferiorSetupRequested);
hjk's avatar
hjk committed
884 885 886 887 888
    m_engine->setupInferior();
}

void DebuggerEngine::notifyInferiorSetupFailed()
{
hjk's avatar
hjk committed
889
    showMessage(_("NOTE: INFERIOR SETUP FAILED"));
hjk's avatar
hjk committed
890
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
hjk's avatar
hjk committed
891
    setState(InferiorSetupFailed);
hjk's avatar
hjk committed
892
    d->queueShutdownEngine();
hjk's avatar
hjk committed
893 894 895 896
}

void DebuggerEngine::notifyInferiorSetupOk()
{
hjk's avatar
hjk committed
897
    showMessage(_("NOTE: INFERIOR SETUP OK"));
hjk's avatar
hjk committed
898
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
hjk's avatar
hjk committed
899
    d->queueRunEngine();
hjk's avatar
hjk committed
900 901 902 903
}

void DebuggerEnginePrivate::doRunEngine()
{
hjk's avatar
hjk committed
904
    m_engine->showMessage(_("CALL: RUN ENGINE"));
hjk's avatar
hjk committed
905
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
906
    m_progress.setProgressValue(300);
hjk's avatar
hjk committed
907 908 909
    m_engine->runEngine();
}

hjk's avatar
hjk committed
910 911
void DebuggerEngine::notifyInferiorUnrunnable()
{
hjk's avatar
hjk committed
912
    showMessage(_("NOTE: INFERIOR UNRUNNABLE"));
913 914
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
915 916 917 918 919 920
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
    setState(InferiorUnrunnable);
}

void DebuggerEngine::notifyEngineRunFailed()
{
hjk's avatar
hjk committed
921
    showMessage(_("NOTE: ENGINE RUN FAILED"));
hjk's avatar
hjk committed
922
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
923 924 925
    d->m_progress.setProgressValue(900);
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
926
    setState(EngineRunFailed);
927
    d->queueShutdownEngine();
hjk's avatar
hjk committed
928 929 930 931
}

void DebuggerEngine::notifyEngineRunAndInferiorRunOk()
{
hjk's avatar
hjk committed
932
    showMessage(_("NOTE: ENGINE RUN AND INFERIOR RUN OK"));
933 934
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
935 936 937 938 939 940 941
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
    setState(InferiorRunRequested);
    notifyInferiorRunOk();
}

void DebuggerEngine::notifyEngineRunAndInferiorStopOk()
{
hjk's avatar
hjk committed
942
    showMessage(_("NOTE: ENGINE RUN AND INFERIOR STOP OK"));
943 944
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
945 946 947 948 949 950 951
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
    setState(InferiorStopRequested);
    notifyInferiorStopOk();
}

void DebuggerEngine::notifyInferiorRunRequested()
{
hjk's avatar
hjk committed
952
    showMessage(_("NOTE: INFERIOR RUN REQUESTED"));
hjk's avatar
hjk committed
953 954 955 956 957 958
    QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
    setState(InferiorRunRequested);
}

void DebuggerEngine::notifyInferiorRunOk()
{
hjk's avatar
hjk committed
959
    showMessage(_("NOTE: INFERIOR RUN OK"));
hjk's avatar
hjk committed
960 961 962 963 964 965
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
    setState(InferiorRunOk);
}

void DebuggerEngine::notifyInferiorRunFailed()
{
hjk's avatar
hjk committed
966
    showMessage(_("NOTE: INFERIOR RUN FAILED"));
hjk's avatar
hjk committed
967 968 969
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
    setState(InferiorRunFailed);
    setState(InferiorStopOk);
hjk's avatar
hjk committed
970 971
    if (isDying())
        d->queueShutdownInferior();
hjk's avatar
hjk committed
972 973 974 975
}

void DebuggerEngine::notifyInferiorStopOk()
{
hjk's avatar
hjk committed
976 977
    showMessage(_("NOTE: INFERIOR STOP OK"));
    // Ignore spurious notifications after we are set to die.
hjk's avatar
hjk committed
978
    if (isDying()) {
hjk's avatar
hjk committed
979 980 981 982 983 984 985 986 987 988 989 990 991
        showMessage(_("NOTE: ... WHILE DYING. "));
        // Forward state to "StopOk" if needed.
        if (state() == InferiorStopRequested
                || state() == InferiorRunRequested
                || state() == InferiorRunOk) {
            showMessage(_("NOTE: ... FORWARDING TO 'STOP OK'. "));
            setState(InferiorStopOk);
        }
        if (state() == InferiorStopOk || state() == InferiorStopFailed) {
            d->queueShutdownInferior();
        }
        showMessage(_("NOTE: ... IGNORING STOP MESSAGE"));
        return;
hjk's avatar
hjk committed
992
    }
hjk's avatar
hjk committed
993 994
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
    setState(InferiorStopOk);
hjk's avatar
hjk committed
995 996
}

hjk's avatar
hjk committed
997
void DebuggerEngine::notifyInferiorSpontaneousStop()
998
{
hjk's avatar
hjk committed
999
    showMessage(_("NOTE: INFERIOR SPONTANEOUES STOP"));
hjk's avatar
hjk committed
1000 1001
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
    setState(InferiorStopOk);
1002 1003
}

hjk's avatar
hjk committed
1004
void DebuggerEngine::notifyInferiorStopFailed()
1005
{
hjk's avatar
hjk committed
1006
    showMessage(_("NOTE: INFERIOR STOP FAILED"));
hjk's avatar
hjk committed
1007 1008
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
    setState(InferiorStopFailed);
hjk's avatar
hjk committed
1009
    d->queueShutdownEngine();
1010 1011 1012 1013
}

void DebuggerEnginePrivate::doInterruptInferior()
{
hjk's avatar
hjk committed
1014 1015
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
    m_engine->setState(InferiorStopRequested);
hjk's avatar
hjk committed
1016
    m_engine->showMessage(_("CALL: INTERRUPT INFERIOR"));
1017 1018 1019
    m_engine->interruptInferior();
}

hjk's avatar
hjk committed
1020 1021
void DebuggerEnginePrivate::doShutdownInferior()
{
1022
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
hjk's avatar
hjk committed
1023 1024
    m_engine->resetLocation();
    m_targetState = DebuggerFinished;
hjk's avatar
hjk committed
1025
    m_engine->showMessage(_("CALL: SHUTDOWN INFERIOR"));
hjk's avatar
hjk committed
1026 1027 1028 1029 1030 1031
    m_engine->shutdownInferior();
}

void DebuggerEngine::notifyInferiorShutdownOk()
{
    showMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
hjk's avatar
hjk committed
1032
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
hjk's avatar
hjk committed
1033 1034
    d->m_lastGoodState = DebuggerNotReady; // A "neutral" value.
    setState(InferiorShutdownOk);
hjk's avatar
hjk committed
1035
    d->queueShutdownEngine();
hjk's avatar
hjk committed
1036 1037 1038 1039 1040
}

void DebuggerEngine::notifyInferiorShutdownFailed()
{
    showMessage(_("INFERIOR SHUTDOWN FAILED"));
Friedemann Kleint's avatar
Friedemann Kleint committed
1041
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << this << state());
hjk's avatar
hjk committed
1042
    setState(InferiorShutdownFailed);
hjk's avatar
hjk committed
1043
    d->queueShutdownEngine();
hjk's avatar
hjk committed
1044 1045