debuggerengine.cpp 50.4 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 52
#include <coreplugin/icore.h>
#include <coreplugin/editormanager/editormanager.h>
53 54
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
hjk's avatar
hjk committed
55

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

#include <qt4projectmanager/qt4projectmanagerconstants.h>

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

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

#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QTimer>
71
#include <QtCore/QFutureInterface>
72 73 74 75

#include <QtGui/QAbstractItemView>
#include <QtGui/QStandardItemModel>
#include <QtGui/QAction>
76
#include <QtGui/QMenu>
77
#include <QtGui/QMessageBox>
hjk's avatar
hjk committed
78
#include <QtGui/QPlainTextEdit>
79
#include <QtGui/QPushButton>
hjk's avatar
hjk committed
80 81
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
82 83
#include <QtGui/QTextDocument>
#include <QtGui/QTreeWidget>
84
#include <QtGui/QMainWindow>
85

hjk's avatar
hjk committed
86
using namespace Core;
87 88
using namespace Debugger;
using namespace Debugger::Internal;
hjk's avatar
hjk committed
89 90
using namespace ProjectExplorer;
using namespace TextEditor;
91

hjk's avatar
hjk committed
92 93 94 95 96 97 98
//#define DEBUG_STATE 1
#if DEBUG_STATE
#   define SDEBUG(s) qDebug() << s
#else
#   define SDEBUG(s)
#endif
# define XSDEBUG(s) qDebug() << s
99 100 101 102 103 104 105

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

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

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


namespace Debugger {

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

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
148
            << " useServerStartScript=" << sp.useServerStartScript
149 150 151 152 153 154 155 156 157 158
            << " 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
159
        SN(EngineSetupRequested)
160 161
        SN(EngineSetupOk)
        SN(EngineSetupFailed)
hjk's avatar
hjk committed
162 163
        SN(EngineRunFailed)
        SN(InferiorSetupRequested)
hjk's avatar
hjk committed
164
        SN(InferiorSetupFailed)
hjk's avatar
hjk committed
165 166 167 168
        SN(EngineRunRequested)
        SN(InferiorRunRequested)
        SN(InferiorRunOk)
        SN(InferiorRunFailed)
169
        SN(InferiorUnrunnable)
hjk's avatar
hjk committed
170 171
        SN(InferiorStopRequested)
        SN(InferiorStopOk)
172
        SN(InferiorStopFailed)
hjk's avatar
hjk committed
173 174
        SN(InferiorShutdownRequested)
        SN(InferiorShutdownOk)
175
        SN(InferiorShutdownFailed)
hjk's avatar
hjk committed
176 177 178 179
        SN(EngineShutdownRequested)
        SN(EngineShutdownOk)
        SN(EngineShutdownFailed)
        SN(DebuggerFinished)
180 181 182 183 184
    }
    return "<unknown>";
#    undef SN
}

185

186 187 188 189 190 191 192 193 194
//////////////////////////////////////////////////////////////////////
//
// CommandHandler
//
//////////////////////////////////////////////////////////////////////

class CommandHandler : public QStandardItemModel
{
public:
195
    explicit CommandHandler(DebuggerEngine *engine) : m_engine(engine) {}
196 197 198 199
    bool setData(const QModelIndex &index, const QVariant &value, int role);
    QAbstractItemModel *model() { return this; }

private:
200
    QPointer<DebuggerEngine> m_engine;
201 202
};

203
bool CommandHandler::setData(const QModelIndex &, const QVariant &value, int role)
204
{
205
    QTC_ASSERT(m_engine, qDebug() << value << role; return false);
206 207
    m_engine->handleCommand(role, value);
    return true;
208 209 210 211 212 213 214 215 216
}


//////////////////////////////////////////////////////////////////////
//
// DebuggerEnginePrivate
//
//////////////////////////////////////////////////////////////////////

217
class DebuggerEnginePrivate : public QObject
218
{
219 220
    Q_OBJECT

221 222 223 224
public:
    DebuggerEnginePrivate(DebuggerEngine *engine, const DebuggerStartParameters &sp)
      : m_engine(engine),
        m_runControl(0),
225
        m_isActive(false),
226 227
        m_startParameters(sp),
        m_state(DebuggerNotReady),
hjk's avatar
hjk committed
228
        m_lastGoodState(DebuggerNotReady),
Friedemann Kleint's avatar
Friedemann Kleint committed
229
        m_targetState(DebuggerNotReady),
230 231 232 233 234 235 236 237
        m_breakHandler(engine),
        m_commandHandler(engine),
        m_modulesHandler(engine),
        m_registerHandler(engine),
        m_sourceFilesHandler(engine),
        m_stackHandler(engine),
        m_threadsHandler(engine),
        m_watchHandler(engine),
238
        m_disassemblerViewAgent(engine),
239
        m_isSlaveEngine(false)
240
    {}
241 242

    ~DebuggerEnginePrivate() {}
243

244 245 246 247 248
public slots:
    void breakpointSetRemoveMarginActionTriggered();
    void breakpointEnableDisableMarginActionTriggered();
    void handleContextMenuRequest(const QVariant &parameters);

hjk's avatar
hjk committed
249 250
    void doSetupInferior();
    void doRunEngine();
hjk's avatar
hjk committed
251 252
    void doShutdownEngine();
    void doShutdownInferior();
253
    void doInterruptInferior();
hjk's avatar
hjk committed
254
    void doFinishDebugger();
hjk's avatar
hjk committed
255

hjk's avatar
hjk committed
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    void queueRunEngine() {
        m_engine->setState(EngineRunRequested);
        m_engine->showMessage(_("QUEUE: RUN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doRunEngine()));
    }

    void queueShutdownEngine() {
        m_engine->setState(EngineShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doShutdownEngine()));
    }

    void queueShutdownInferior() {
        m_engine->setState(InferiorShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN INFERIOR"));
        QTimer::singleShot(0, this, SLOT(doShutdownInferior()));
    }

    void queueFinishDebugger() {
275 276 277 278
        QTC_ASSERT(state() == EngineShutdownOk
            || state() == EngineShutdownFailed, qDebug() << state());
        m_engine->setState(DebuggerFinished);
        m_engine->showMessage(_("QUEUE: FINISH DEBUGGER"));
hjk's avatar
hjk committed
279 280 281
        QTimer::singleShot(0, this, SLOT(doFinishDebugger()));
    }

282
    void raiseApplication() {
hjk's avatar
hjk committed
283
        QTC_ASSERT(m_runControl, return);
284 285 286
        m_runControl->bringApplicationToForeground(m_inferiorPid);
    }

287 288
private slots:
    void slotEditBreakpoint();
289

290
public:
hjk's avatar
hjk committed
291 292
    DebuggerState state() const { return m_state; }

293 294
    DebuggerEngine *m_engine; // Not owned.
    DebuggerRunControl *m_runControl;  // Not owned.
295
    bool m_isActive;
296 297

    DebuggerStartParameters m_startParameters;
hjk's avatar
hjk committed
298 299

    // The current state.
300 301
    DebuggerState m_state;

hjk's avatar
hjk committed
302 303 304 305 306 307
    // The state we had before something unexpected happend.
    DebuggerState m_lastGoodState;

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

308 309 310 311 312 313 314 315 316 317 318
    qint64 m_inferiorPid;

    BreakHandler m_breakHandler;
    CommandHandler m_commandHandler;
    ModulesHandler m_modulesHandler;
    RegisterHandler m_registerHandler;
    SourceFilesHandler m_sourceFilesHandler;
    StackHandler m_stackHandler;
    ThreadsHandler m_threadsHandler;
    WatchHandler m_watchHandler;
    DisassemblerViewAgent m_disassemblerViewAgent;
319
    QFutureInterface<void> m_progress;
320

321
    bool m_isSlaveEngine;
322 323
};

324 325 326 327 328
void DebuggerEnginePrivate::breakpointSetRemoveMarginActionTriggered()
{
    QAction *act = qobject_cast<QAction *>(sender());
    QTC_ASSERT(act, return);
    QList<QVariant> list = act->data().toList();
329
    QTC_ASSERT(list.size() >= 3, qDebug() << list; return);
330 331
    const QString fileName = list.at(0).toString();
    const int lineNumber = list.at(1).toInt();
332 333
    const quint64 address = list.at(2).toULongLong();
    m_breakHandler.toggleBreakpoint(fileName, lineNumber, address);
334 335
}

336 337 338 339 340 341 342
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
343
    BreakWindow::editBreakpoint(breakPointData, ICore::instance()->mainWindow());
344 345
}

346 347 348 349 350
void DebuggerEnginePrivate::breakpointEnableDisableMarginActionTriggered()
{
    QAction *act = qobject_cast<QAction *>(sender());
    QTC_ASSERT(act, return);
    QList<QVariant> list = act->data().toList();
351
    QTC_ASSERT(list.size() == 3, qDebug() << list; return);
352 353 354 355 356 357 358 359
    const QString fileName = list.at(0).toString();
    const int lineNumber = list.at(1).toInt();
    m_breakHandler.toggleBreakpointEnabled(fileName, lineNumber);
}

void DebuggerEnginePrivate::handleContextMenuRequest(const QVariant &parameters)
{
    const QList<QVariant> list = parameters.toList();
360
    QTC_ASSERT(list.size() == 3, qDebug() << list; return);
hjk's avatar
hjk committed
361
    TextEditor::ITextEditor *editor =
362 363 364 365 366 367
        (TextEditor::ITextEditor *)(list.at(0).value<quint64>());
    int lineNumber = list.at(1).toInt();
    QMenu *menu = (QMenu *)(list.at(2).value<quint64>());

    BreakpointData *data = 0;
    QString fileName;
368
    quint64 address = 0;
369 370 371 372 373
    if (editor->property("DisassemblerView").toBool()) {
        fileName = editor->file()->fileName();
        QString line = editor->contents()
            .section('\n', lineNumber - 1, lineNumber - 1);
        BreakpointData needle;
374 375
        address = needle.address = DisassemblerViewAgent::addressFromDisassemblyLine(line);
        needle.bpLineNumber = -1;
376 377 378 379 380 381 382 383 384
        data = m_breakHandler.findSimilarBreakpoint(&needle);
    } else {
        fileName = editor->file()->fileName();
        data = m_breakHandler.findBreakpoint(fileName, lineNumber);
    }

    QList<QVariant> args;
    args.append(fileName);
    args.append(lineNumber);
385
    args.append(address);
386 387 388

    if (data) {
        // existing breakpoint
389
        const QString number = QString::fromAscii(data->bpNumber);
390 391 392 393 394
        QAction *act;
        if (number.isEmpty())
            act = new QAction(tr("Remove Breakpoint"), menu);
        else
            act = new QAction(tr("Remove Breakpoint %1").arg(number), menu);
395 396 397 398 399 400 401
        act->setData(args);
        connect(act, SIGNAL(triggered()),
            this, SLOT(breakpointSetRemoveMarginActionTriggered()));
        menu->addAction(act);

        QAction *act2;
        if (data->enabled)
402 403 404 405
            if (number.isEmpty())
                act2 = new QAction(tr("Disable Breakpoint"), menu);
            else
                act2 = new QAction(tr("Disable Breakpoint %1").arg(number), menu);
406
        else
407 408 409 410
            if (number.isEmpty())
                act2 = new QAction(tr("Enable Breakpoint"), menu);
            else
                act2 = new QAction(tr("Enable Breakpoint %1").arg(number), menu);
411 412 413 414
        act2->setData(args);
        connect(act2, SIGNAL(triggered()),
            this, SLOT(breakpointEnableDisableMarginActionTriggered()));
        menu->addAction(act2);
415 416 417 418 419
        QAction *editAction;
        if (number.isEmpty())
            editAction = new QAction(tr("Edit Breakpoint..."), menu);
        else
            editAction = new QAction(tr("Edit Breakpoint %1...").arg(number), menu);
420 421 422
        connect(editAction, SIGNAL(triggered()), this, SLOT(slotEditBreakpoint()));
        editAction->setData(qVariantFromValue(data));
        menu->addAction(editAction);
423 424
    } else {
        // non-existing
425 426 427 428
        const QString text = address ?
                    tr("Set Breakpoint at 0x%1").arg(address, 0, 16) :
                    tr("Set Breakpoint at line %1").arg(lineNumber);
        QAction *act = new QAction(text, menu);
429 430 431 432 433 434
        act->setData(args);
        connect(act, SIGNAL(triggered()),
            this, SLOT(breakpointSetRemoveMarginActionTriggered()));
        menu->addAction(act);
    }
}
435 436 437 438 439 440 441 442 443 444 445 446 447 448

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

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

DebuggerEngine::~DebuggerEngine()
{
449 450
    disconnect();
    delete d;
451 452
}

453
void DebuggerEngine::showStatusMessage(const QString &msg, int timeout) const
454
{
455
    showMessage(msg, StatusBar, timeout);
456
}
457

458 459 460 461 462 463
void DebuggerEngine::removeTooltip()
{
    watchHandler()->removeTooltip();
    hideDebuggerToolTip();
}

464 465
void DebuggerEngine::handleCommand(int role, const QVariant &value)
{
466 467
    if (role != RequestToolTipByExpressionRole)
        removeTooltip();
468 469

    switch (role) {
470 471 472 473 474 475 476 477
        case RequestActivateFrameRole:
            activateFrame(value.toInt());
            break;

        case RequestReloadFullStackRole:
            reloadFullStack();
            break;

478 479 480 481 482 483 484 485
        case RequestReloadSourceFilesRole:
            reloadSourceFiles();
            break;

        case RequestReloadModulesRole:
            reloadModules();
            break;

486 487 488 489
        case RequestReloadRegistersRole:
            reloadRegisters();
            break;

490 491 492 493
        case RequestExecDetachRole:
            detachDebugger();
            break;

494 495 496 497 498
        case RequestExecContinueRole:
            continueInferior();
            break;

        case RequestExecInterruptRole:
499
            requestInterruptInferior();
500 501 502
            break;

        case RequestExecResetRole:
503
            notifyEngineIll(); // FIXME: check
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
            break;

        case RequestExecStepRole:
            executeStepX();
            break;

        case RequestExecStepOutRole:
            executeStepOutX();
            break;

        case RequestExecNextRole:
            executeStepNextX();
            break;

        case RequestExecRunToLineRole:
hjk's avatar
hjk committed
519
            executeRunToLine();
520 521 522
            break;

        case RequestExecRunToFunctionRole:
hjk's avatar
hjk committed
523
            executeRunToFunction();
524 525 526 527 528 529 530
            break;

        case RequestExecReturnFromFunctionRole:
            executeReturnX();
            break;

        case RequestExecJumpToLineRole:
hjk's avatar
hjk committed
531
            executeJumpToLine();
532 533 534
            break;

        case RequestExecWatchRole:
hjk's avatar
hjk committed
535
            addToWatchWindow();
536 537 538
            break;

        case RequestExecExitRole:
539
            d->queueShutdownInferior();
540 541
            break;

542 543
        case RequestCreateSnapshotRole:
            createSnapshot();
544 545
            break;

546 547 548 549
        case RequestActivationRole:
            setActive(value.toBool());
            break;

550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
        case RequestExecFrameDownRole:
            frameDown();
            break;

        case RequestExecFrameUpRole:
            frameUp();
            break;

        case RequestOperatedByInstructionTriggeredRole:
            gotoLocation(stackHandler()->currentFrame(), true);
            break;

        case RequestExecuteCommandRole:
            executeDebuggerCommand(value.toString());
            break;
hjk's avatar
hjk committed
565

566 567 568 569 570 571 572 573 574
        case RequestToggleBreakpointRole: {
            QList<QVariant> list = value.toList();
            QTC_ASSERT(list.size() == 2, break);
            const QString fileName = list.at(0).toString();
            const int lineNumber = list.at(1).toInt();
            breakHandler()->toggleBreakpoint(fileName, lineNumber);
            break;
        }

575 576 577
        case RequestToolTipByExpressionRole: {
            QList<QVariant> list = value.toList();
            QTC_ASSERT(list.size() == 3, break);
578 579 580
            QPoint point = list.at(0).value<QPoint>();
            TextEditor::ITextEditor *editor = // Eeks.
                (TextEditor::ITextEditor *)(list.at(1).value<quint64>());
hjk's avatar
hjk committed
581
            int pos = list.at(2).toInt();
582
            setToolTipExpression(point, editor, pos);
583 584 585
            break;
        }

586
        case RequestContextMenuRole: {
587
            QList<QVariant> list = value.toList();
588 589
            QTC_ASSERT(list.size() == 3, break);
            d->handleContextMenuRequest(list);
hjk's avatar
hjk committed
590
            break;
591
        }
592 593 594 595 596 597

        case RequestShowMemoryRole: {
            qDebug() << "CREATING MEMORY VIEW";
            (void) MemoryViewAgent(this, "0x0");
            break;
        }
598
    }
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 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662

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

BreakHandler *DebuggerEngine::breakHandler() const
{
    return &d->m_breakHandler;
}

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

663 664 665 666
//SnapshotHandler *DebuggerEngine::snapshotHandler() const
//{
//    return &d->m_snapshotHandler;
//}
667 668 669 670 671 672 673 674

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

QAbstractItemModel *DebuggerEngine::modulesModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
675 676 677 678
    QAbstractItemModel *model = d->m_modulesHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ModulesModel"));
    return model;
679 680 681 682
}

QAbstractItemModel *DebuggerEngine::breakModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
683 684 685 686
    QAbstractItemModel *model = d->m_breakHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("BreakModel"));
    return model;
687 688 689 690
}

QAbstractItemModel *DebuggerEngine::registerModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
691 692 693 694
    QAbstractItemModel *model = d->m_registerHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("RegisterModel"));
    return model;
695 696 697 698
}

QAbstractItemModel *DebuggerEngine::stackModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
699 700 701 702
    QAbstractItemModel *model = d->m_stackHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("StackModel"));
    return model;
703 704 705 706
}

QAbstractItemModel *DebuggerEngine::threadsModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
707 708 709 710
    QAbstractItemModel *model = d->m_threadsHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ThreadsModel"));
    return model;
711 712 713 714
}

QAbstractItemModel *DebuggerEngine::localsModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
715 716 717 718
    QAbstractItemModel *model = d->m_watchHandler.model(LocalsWatch);
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("LocalsModel"));
    return model;
719 720 721 722
}

QAbstractItemModel *DebuggerEngine::watchersModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
723 724 725 726
    QAbstractItemModel *model = d->m_watchHandler.model(WatchersWatch);
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("WatchersModel"));
    return model;
727 728 729 730
}

QAbstractItemModel *DebuggerEngine::returnModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
731 732 733 734
    QAbstractItemModel *model = d->m_watchHandler.model(ReturnWatch);
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ReturnModel"));
    return model;
735 736 737 738
}

QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
739 740 741 742
    QAbstractItemModel *model = d->m_sourceFilesHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("SourceFilesModel"));
    return model;
743 744 745 746
}

QAbstractItemModel *DebuggerEngine::commandModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
747 748 749 750
    QAbstractItemModel *model = d->m_commandHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("CommandModel"));
    return model;
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
}

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
{
768 769
    //if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
    //    qDebug() << qPrintable(msg) << "IN STATE" << state();
770
    plugin()->showMessage(msg, channel, timeout);
771 772 773 774 775
    if (d->m_runControl) {
        d->m_runControl->showMessage(msg, channel);
    } else {
        qWarning("Warning: %s (no active run control)", qPrintable(msg));
    }
776 777 778 779
}

void DebuggerEngine::startDebugger(DebuggerRunControl *runControl)
{
780
    if (!isSessionEngine() && !isSlaveEngine()) {
781
        d->m_progress.setProgressRange(0, 1000);
782 783 784
        Core::FutureProgress *fp = Core::ICore::instance()->progressManager()
            ->addTask(d->m_progress.future(),
            tr("Launching"), _("Debugger.Launcher"));
785
        fp->setKeepOnFinish(Core::FutureProgress::DontKeepOnFinish);
786 787
        d->m_progress.reportStarted();
    }
788 789
    QTC_ASSERT(runControl, notifyEngineSetupFailed(); return);
    QTC_ASSERT(!d->m_runControl, notifyEngineSetupFailed(); return);
790 791

    DebuggerEngine *sessionTemplate = plugin()->sessionTemplate();
792 793
    QTC_ASSERT(sessionTemplate, notifyEngineSetupFailed(); return);
    QTC_ASSERT(sessionTemplate != this, notifyEngineSetupFailed(); return);
794 795

    breakHandler()->initializeFromTemplate(sessionTemplate->breakHandler());
796
    watchHandler()->initializeFromTemplate(sessionTemplate->watchHandler());
797 798 799 800 801 802 803

    d->m_runControl = runControl;

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

    if (d->m_startParameters.environment.empty())
804
        d->m_startParameters.environment = Utils::Environment().toStringList();
805 806 807 808 809 810 811 812

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

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

813 814
    QTC_ASSERT(state() == DebuggerNotReady || state() == DebuggerFinished,
         qDebug() << state());
hjk's avatar
hjk committed
815
    setState(EngineSetupRequested);
816

817
    d->m_progress.setProgressValue(200);
hjk's avatar
hjk committed
818
    setupEngine();
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
}

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)
{
    d->m_breakHandler.breakByFunction(functionName);
    attemptBreakpointSynchronization();
}

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);
    }
}

void DebuggerEngine::executeStepX()
{
    resetLocation();
    if (theDebuggerBoolSetting(OperateByInstruction))
        executeStepI();
    else
        executeStep();
}

void DebuggerEngine::executeStepOutX()
{
    resetLocation();
    executeStepOut();
}

void DebuggerEngine::executeStepNextX()
{
    resetLocation();
    if (theDebuggerBoolSetting(OperateByInstruction))
        executeNextI();
    else
        executeNext();
}

void DebuggerEngine::executeReturnX()
{
    resetLocation();
    executeReturn();
}

hjk's avatar
hjk committed
893
static TextEditor::ITextEditor *currentTextEditor()
894
{
hjk's avatar
hjk committed
895 896 897 898 899
    EditorManager *editorManager = EditorManager::instance();
    if (!editorManager)
        return 0;
    Core::IEditor *editor = editorManager->currentEditor();
    return qobject_cast<ITextEditor*>(editor);
900 901
}

hjk's avatar
hjk committed
902
void DebuggerEngine::executeRunToLine()
903
{
hjk's avatar
hjk committed
904
    ITextEditor *textEditor = currentTextEditor();
905 906
    QTC_ASSERT(textEditor, return);
    QString fileName = textEditor->file()->fileName();
hjk's avatar
hjk committed
907 908
    if (fileName.isEmpty())
        return;
909
    int lineNumber = textEditor->currentLine();
hjk's avatar
hjk committed
910 911
    resetLocation();
    executeRunToLine(fileName, lineNumber);
912 913
}

hjk's avatar
hjk committed
914
void DebuggerEngine::executeRunToFunction()
915
{
hjk's avatar
hjk committed
916
    ITextEditor *textEditor = currentTextEditor();
917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
    QTC_ASSERT(textEditor, return);
    QString fileName = textEditor->file()->fileName();
    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
941 942 943 944
    if (functionName.isEmpty())
        return;
    resetLocation();
    executeRunToFunction(functionName);
945 946
}

hjk's avatar
hjk committed
947
void DebuggerEngine::executeJumpToLine()
948
{
hjk's avatar
hjk committed
949
    ITextEditor *textEditor = currentTextEditor();
950 951 952
    QTC_ASSERT(textEditor, return);
    QString fileName = textEditor->file()->fileName();
    int lineNumber = textEditor->currentLine();
hjk's avatar
hjk committed
953 954 955
    if (fileName.isEmpty())
        return;
    executeJumpToLine(fileName, lineNumber);
956 957
}

hjk's avatar
hjk committed
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
void DebuggerEngine::addToWatchWindow()
{
    // Requires a selection, but that's the only case we want anyway.
    EditorManager *editorManager = EditorManager::instance();
    if (!editorManager)
        return;
    IEditor *editor = editorManager->currentEditor();
    if (!editor)
        return;
    ITextEditor *textEditor = qobject_cast<ITextEditor*>(editor);
    if (!textEditor)
        return;
    QTextCursor tc;
    QPlainTextEdit *ptEdit = qobject_cast<QPlainTextEdit*>(editor->widget());
    if (ptEdit)
        tc = ptEdit->textCursor();
    QString exp;
    if (tc.hasSelection()) {
        exp = tc.selectedText();
    } else {
        int line, column;
        exp = cppExpressionAt(textEditor, tc.position(), &line, &column);
    }
981 982 983
    if (exp.isEmpty())
        return;
    watchHandler()->watchExpression(exp);
hjk's avatar
hjk committed
984 985
}

986 987 988
// Called from RunControl.
void DebuggerEngine::handleStartFailed()
{
989
    showMessage("HANDLE RUNCONTROL START FAILED");
990
    d->m_runControl = 0;
991

992
    d->m_progress.setProgressValue(900);
993 994
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
995 996
}

997 998
// Called from RunControl.
void DebuggerEngine::handleFinished()
999
{
1000
    showMessage("HANDLE RUNCONTROL FINISHED");
1001
    d->m_runControl = 0;
1002 1003 1004 1005
    modulesHandler()->removeAll();
    stackHandler()->removeAll();
    threadsHandler()->removeAll();
    watchHandler()->cleanup();
1006 1007

    DebuggerEngine *sessionTemplate = plugin()->sessionTemplate();
1008 1009
    QTC_ASSERT(sessionTemplate != this, /**/);
    breakHandler()->storeToTemplate(sessionTemplate->breakHandler());
1010
    watchHandler()->storeToTemplate(sessionTemplate->watchHandler());
1011

1012
    d->m_progress.setProgressValue(1000);
1013
    d->m_progress.reportFinished();
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054
}

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)
{
1055
    QMessageBox dialog(plugin()->mainWindow());
Leena Miettinen's avatar
Leena Miettinen committed
1056
    QPushButton *qtPref = dialog.addButton(tr("Open Qt4 Options"),
1057
        QMessageBox::ActionRole);
Leena Miettinen's avatar
Leena Miettinen committed
1058
    QPushButton *helperOff = dialog.addButton(tr("Turn off Helper Usage"),
1059
        QMessageBox::ActionRole);
Leena Miettinen's avatar
Leena Miettinen committed
1060
    QPushButton *justContinue = dialog.addButton(tr("Continue Anyway"),
1061 1062
        QMessageBox::AcceptRole);
    dialog.setDefaultButton(justContinue);
Leena Miettinen's avatar
Leena Miettinen committed
1063
    dialog.setWindowTitle(tr("Debugging Helper Missing"));
1064 1065 1066 1067 1068
    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
1069 1070
        "On the Qt4 options page, select a Qt installation "
        "and click Rebuild."));
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
    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
1096
DebuggerState DebuggerEngine::lastGoodState() const
1097
{
hjk's avatar
hjk committed
1098 1099 1100 1101 1102 1103 1104
    return d->m_lastGoodState;
}

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

hjk's avatar
hjk committed
1106 1107 1108
static bool isAllowedTransition(DebuggerState from, DebuggerState to)
{
    switch (from) {
1109
    case DebuggerNotReady:
1110
        return to == EngineSetupRequested;
1111

hjk's avatar
hjk committed
1112
    case EngineSetupRequested:
1113 1114
        return to == EngineSetupOk || to == EngineSetupFailed;
    case EngineSetupFailed: