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>
dt's avatar
dt committed
57
#include <projectexplorer/toolchain.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 116 117
    toolChainType(ToolChain::UNKNOWN),
    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 239
        m_disassemblerViewAgent(engine),
        m_runInWrapperEngine(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_runInWrapperEngine;
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 343 344 345 346
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);
    if (BreakWindow::editBreakpoint(breakPointData, ICore::instance()->mainWindow()))
        breakPointData->reinsertBreakpoint();
}

347 348 349 350 351
void DebuggerEnginePrivate::breakpointEnableDisableMarginActionTriggered()
{
    QAction *act = qobject_cast<QAction *>(sender());
    QTC_ASSERT(act, return);
    QList<QVariant> list = act->data().toList();
352
    QTC_ASSERT(list.size() == 3, qDebug() << list; return);
353 354 355 356 357 358 359 360
    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();
361
    QTC_ASSERT(list.size() == 3, qDebug() << list; return);
hjk's avatar
hjk committed
362
    TextEditor::ITextEditor *editor =
363 364 365 366 367 368
        (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;
369
    quint64 address = 0;
370 371 372 373 374
    if (editor->property("DisassemblerView").toBool()) {
        fileName = editor->file()->fileName();
        QString line = editor->contents()
            .section('\n', lineNumber - 1, lineNumber - 1);
        BreakpointData needle;
375 376
        address = needle.address = DisassemblerViewAgent::addressFromDisassemblyLine(line);
        needle.bpLineNumber = -1;
377 378 379 380 381 382 383 384 385
        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);
386
    args.append(address);
387 388 389

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

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

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

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

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

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

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

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

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

        case RequestReloadFullStackRole:
            reloadFullStack();
            break;

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

        case RequestReloadModulesRole:
            reloadModules();
            break;

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

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

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

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

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

        case RequestExecStepRole:
            executeStepX();
            break;

        case RequestExecStepOutRole:
            executeStepOutX();
            break;

        case RequestExecNextRole:
            executeStepNextX();
            break;

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

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

        case RequestExecReturnFromFunctionRole:
            executeReturnX();
            break;

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

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

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

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

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

551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
        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
566

567 568 569 570 571 572 573 574 575
        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;
        }

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

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

        case RequestShowMemoryRole: {
            qDebug() << "CREATING MEMORY VIEW";
            (void) MemoryViewAgent(this, "0x0");
            break;
        }
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 663

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    d->m_runControl = runControl;

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

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

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

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

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

818
    d->m_progress.setProgressValue(200);
hjk's avatar
hjk committed
819
    setupEngine();
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 893
}

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

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

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

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

hjk's avatar
hjk committed
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981
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);
    }
982 983 984
    if (exp.isEmpty())
        return;
    watchHandler()->watchExpression(exp);
hjk's avatar
hjk committed
985 986
}

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

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

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

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

1013
    d->m_progress.setProgressValue(1000);
1014
    d->m_progress.reportFinished();
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 1055
}

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

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

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

hjk's avatar
hjk committed
1113
    case EngineSetupRequested:
1114 1115
        return to == EngineSetupOk || to == EngineSetupFailed;
    case EngineSetupFailed:
1116
        // FIXME: In therory it's the engine's task to go into a
1117 1118 1119
        // proper "Shutdown" state before calling notifyEngineSetupFailed
        //return to == DebuggerFinished;
        return to == EngineShutdownRequested;
1120
    case EngineSetupOk:
hjk's avatar
hjk committed
1121