lldbengine.cpp 41.7 KB
Newer Older
1 2
/****************************************************************************
**
Eike Ziller's avatar
Eike Ziller committed
3 4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
5 6 7 8 9 10 11
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
Eike Ziller's avatar
Eike Ziller committed
12 13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
15 16 17
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18 19 20 21 22 23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24
**
Eike Ziller's avatar
Eike Ziller committed
25 26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
27 28 29 30 31 32
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "lldbengine.h"

33 34 35
#include <debugger/debuggeractions.h>
#include <debugger/debuggercore.h>
#include <debugger/debuggerdialogs.h>
Fawzi Mohamed's avatar
Fawzi Mohamed committed
36
#include <debugger/debuggerinternalconstants.h>
37
#include <debugger/debuggermainwindow.h>
38 39 40 41
#include <debugger/debuggerprotocol.h>
#include <debugger/debuggerstartparameters.h>
#include <debugger/debuggerstringutils.h>
#include <debugger/debuggertooltipmanager.h>
42

43 44 45 46 47 48 49 50 51
#include <debugger/breakhandler.h>
#include <debugger/disassemblerlines.h>
#include <debugger/moduleshandler.h>
#include <debugger/registerhandler.h>
#include <debugger/stackhandler.h>
#include <debugger/sourceutils.h>
#include <debugger/threadshandler.h>
#include <debugger/watchhandler.h>
#include <debugger/watchutils.h>
52

53
#include <coreplugin/messagebox.h>
54 55 56
#include <coreplugin/idocument.h>
#include <coreplugin/icore.h>

hjk's avatar
hjk committed
57 58 59 60 61
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
#include <utils/qtcprocess.h>

#include <QApplication>
62 63 64 65 66 67
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QTimer>
#include <QToolTip>
hjk's avatar
hjk committed
68
#include <QVariant>
69

hjk's avatar
hjk committed
70
using namespace Core;
hjk's avatar
hjk committed
71 72
using namespace Utils;

73 74 75
namespace Debugger {
namespace Internal {

76 77 78 79 80 81
static int &currentToken()
{
    static int token = 0;
    return token;
}

82 83 84 85 86 87 88
///////////////////////////////////////////////////////////////////////
//
// LldbEngine
//
///////////////////////////////////////////////////////////////////////

LldbEngine::LldbEngine(const DebuggerStartParameters &startParameters)
89
    : DebuggerEngine(startParameters), m_continueAtNextSpontaneousStop(false)
90
{
91
    m_lastAgentId = 0;
92
    setObjectName(QLatin1String("LldbEngine"));
93

hjk's avatar
hjk committed
94 95 96 97
    if (startParameters.useTerminal) {
        #ifdef Q_OS_WIN
            // Windows up to xp needs a workaround for attaching to freshly started processes. see proc_stub_win
            if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
hjk's avatar
hjk committed
98
                m_stubProc.setMode(ConsoleProcess::Suspend);
hjk's avatar
hjk committed
99
            else
hjk's avatar
hjk committed
100
                m_stubProc.setMode(ConsoleProcess::Debug);
hjk's avatar
hjk committed
101
        #else
hjk's avatar
hjk committed
102 103
            m_stubProc.setMode(ConsoleProcess::Debug);
            m_stubProc.setSettings(ICore::settings());
hjk's avatar
hjk committed
104 105 106
        #endif
    }

hjk's avatar
hjk committed
107 108 109 110 111 112 113 114 115 116
    connect(action(AutoDerefPointers), &SavedAction::valueChanged,
            this, &LldbEngine::updateLocals);
    connect(action(CreateFullBacktrace), &QAction::triggered,
            this, &LldbEngine::createFullBacktrace);
    connect(action(UseDebuggingHelpers), &SavedAction::valueChanged,
            this, &LldbEngine::updateLocals);
    connect(action(UseDynamicType), &SavedAction::valueChanged,
            this, &LldbEngine::updateLocals);
    connect(action(IntelFlavor), &SavedAction::valueChanged,
            this, &LldbEngine::updateAll);
117 118 119
}

LldbEngine::~LldbEngine()
hjk's avatar
hjk committed
120 121
{
    m_stubProc.disconnect(); // Avoid spurious state transitions from late exiting stub
122
    m_lldbProc.disconnect();
hjk's avatar
hjk committed
123 124
}

hjk's avatar
hjk committed
125
void LldbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages)
126
{
127 128 129
    DebuggerCommand cmd("executeDebuggerCommand");
    cmd.arg("command", command);
    runCommand(cmd);
130 131
}

132
void LldbEngine::runCommand(const DebuggerCommand &command_)
133 134
{
    QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll());
135 136 137 138
    const int tok = ++currentToken();
    DebuggerCommand command = command_;
    command.arg("token", tok);
    QByteArray token = QByteArray::number(tok);
139 140
    QByteArray cmd  = command.function + "({" + command.args + "})";
    showMessage(_(token + cmd + '\n'), LogInput);
hjk's avatar
hjk committed
141
    m_lldbProc.write("script theDumper." + cmd + "\n");
142 143
}

144 145 146 147 148
void LldbEngine::debugLastCommand()
{
    runCommand(m_lastDebuggableCommand);
}

149 150 151
void LldbEngine::shutdownInferior()
{
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
152
    runCommand(DebuggerCommand("shutdownInferior"));
153 154 155 156 157 158
}

void LldbEngine::shutdownEngine()
{
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
    m_lldbProc.kill();
hjk's avatar
hjk committed
159 160
    if (startParameters().useTerminal)
        m_stubProc.stop();
161
    notifyEngineShutdownOk();
162 163
}

164 165 166 167 168 169 170 171 172 173 174 175 176
void LldbEngine::abortDebugger()
{
    if (targetState() == DebuggerFinished) {
        // We already tried. Try harder.
        showMessage(_("ABORTING DEBUGGER. SECOND TIME."));
        m_lldbProc.kill();
    } else {
        // Be friendly the first time. This will change targetState().
        showMessage(_("ABORTING DEBUGGER. FIRST TIME."));
        quitDebugger();
    }
}

hjk's avatar
hjk committed
177 178 179 180 181 182 183
// FIXME: Merge with GdbEngine/QtcProcess
bool LldbEngine::prepareCommand()
{
    if (HostOsInfo::isWindowsHost()) {
        DebuggerStartParameters &sp = startParameters();
        QtcProcess::SplitError perr;
        sp.processArgs = QtcProcess::prepareArgs(sp.processArgs, &perr,
hjk's avatar
hjk committed
184
                                                 HostOsInfo::hostOs(),
hjk's avatar
hjk committed
185
                    &sp.environment, &sp.workingDirectory).toWindowsArgs();
hjk's avatar
hjk committed
186
        if (perr != QtcProcess::SplitOk) {
hjk's avatar
hjk committed
187 188 189 190 191 192 193 194 195
            // perr == BadQuoting is never returned on Windows
            // FIXME? QTCREATORBUG-2809
            notifyEngineSetupFailed();
            return false;
        }
    }
    return true;
}

196 197
void LldbEngine::setupEngine()
{
hjk's avatar
hjk committed
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
    if (startParameters().useTerminal) {
        QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
        showMessage(_("TRYING TO START ADAPTER"));

    // Currently, adapters are not re-used
    //    // We leave the console open, so recycle it now.
    //    m_stubProc.blockSignals(true);
    //    m_stubProc.stop();
    //    m_stubProc.blockSignals(false);

        if (!prepareCommand()) {
            notifyEngineSetupFailed();
            return;
        }

        m_stubProc.setWorkingDirectory(startParameters().workingDirectory);
        // Set environment + dumper preload.
        m_stubProc.setEnvironment(startParameters().environment);

hjk's avatar
hjk committed
217 218 219
        connect(&m_stubProc, &ConsoleProcess::processError, this, &LldbEngine::stubError);
        connect(&m_stubProc, &ConsoleProcess::processStarted, this, &LldbEngine::stubStarted);
        connect(&m_stubProc, &ConsoleProcess::stubStopped, this, &LldbEngine::stubExited);
hjk's avatar
hjk committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
        // FIXME: Starting the stub implies starting the inferior. This is
        // fairly unclean as far as the state machine and error reporting go.

        if (!m_stubProc.start(startParameters().executable,
                             startParameters().processArgs)) {
            // Error message for user is delivered via a signal.
            //handleAdapterStartFailed(QString());
            notifyEngineSetupFailed();
            return;
        }

    } else {
        QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
        if (startParameters().remoteSetupNeeded)
            notifyEngineRequestRemoteSetup();
        else
            startLldb();
    }
Fawzi Mohamed's avatar
Fawzi Mohamed committed
238
}
239

Fawzi Mohamed's avatar
Fawzi Mohamed committed
240 241
void LldbEngine::startLldb()
{
242
    m_lldbCmd = startParameters().debuggerCommand;
hjk's avatar
hjk committed
243 244 245 246 247 248 249 250 251 252 253
    connect(&m_lldbProc, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
            this, &LldbEngine::handleLldbError);
    connect(&m_lldbProc, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
            this, &LldbEngine::handleLldbFinished);
    connect(&m_lldbProc, &QProcess::readyReadStandardOutput,
            this, &LldbEngine::readLldbStandardOutput);
    connect(&m_lldbProc, &QProcess::readyReadStandardError,
            this, &LldbEngine::readLldbStandardError);

    connect(this, &LldbEngine::outputReady,
            this, &LldbEngine::handleResponse, Qt::QueuedConnection);
254

255
    showMessage(_("STARTING LLDB: ") + m_lldbCmd);
256
    m_lldbProc.setEnvironment(startParameters().environment.toStringList());
Eike Ziller's avatar
Eike Ziller committed
257 258
    if (!startParameters().workingDirectory.isEmpty())
        m_lldbProc.setWorkingDirectory(startParameters().workingDirectory);
259

260
    m_lldbProc.start(m_lldbCmd);
261 262

    if (!m_lldbProc.waitForStarted()) {
263
        const QString msg = tr("Unable to start LLDB \"%1\": %2")
264
            .arg(m_lldbCmd, m_lldbProc.errorString());
265 266
        notifyEngineSetupFailed();
        showMessage(_("ADAPTER START FAILED"));
267
        if (!msg.isEmpty())
hjk's avatar
hjk committed
268
            ICore::showWarningWithOptions(tr("Adapter start failed."), msg);
269
        return;
270
    }
271 272 273
    m_lldbProc.waitForReadyRead(1000);
    m_lldbProc.write("sc print('@\\nlldbstartupok@\\n')\n");
}
274

275 276 277
// FIXME: splitting of startLldb() necessary to support LLDB <= 310 - revert asap
void LldbEngine::startLldbStage2()
{
278 279 280 281 282 283
    showMessage(_("ADAPTER STARTED"));
    showStatusMessage(tr("Setting up inferior..."));

    const QByteArray dumperSourcePath =
        ICore::resourcePath().toLocal8Bit() + "/debugger/";

hjk's avatar
hjk committed
284 285 286 287
    m_lldbProc.write("script sys.path.insert(1, '" + dumperSourcePath + "')\n");
    m_lldbProc.write("script from lldbbridge import *\n");
    m_lldbProc.write("script print(dir())\n");
    m_lldbProc.write("script theDumper = Dumper()\n"); // This triggers reportState("enginesetupok")
288 289 290 291
}

void LldbEngine::setupInferior()
{
hjk's avatar
hjk committed
292
    const QString path = stringSetting(ExtraDumperFile);
293
    if (!path.isEmpty()) {
294
        DebuggerCommand cmd("addDumperModule");
295 296
        cmd.arg("path", path.toUtf8());
        runCommand(cmd);
297 298
    }

hjk's avatar
hjk committed
299
    const QString commands = stringSetting(ExtraDumperCommands);
300
    if (!commands.isEmpty()) {
301
        DebuggerCommand cmd("executeDebuggerCommand");
hjk's avatar
hjk committed
302
        cmd.arg("commands", commands.toUtf8());
303 304 305
        runCommand(cmd);
    }

306
    DebuggerCommand cmd1("loadDumpers");
hjk's avatar
hjk committed
307
    runCommand(cmd1);
308 309 310 311 312 313
}

// FIXME: splitting of setupInferior() necessary to support LLDB <= 310 - revert asap
void LldbEngine::setupInferiorStage2()
{
    const DebuggerStartParameters &sp = startParameters();
hjk's avatar
hjk committed
314

315
    QString executable;
hjk's avatar
hjk committed
316 317 318
    QtcProcess::Arguments args;
    QtcProcess::prepareCommand(QFileInfo(sp.executable).absoluteFilePath(),
                               sp.processArgs, &executable, &args);
319

320
    DebuggerCommand cmd("setupInferior");
321
    cmd.arg("executable", executable);
322
    cmd.arg("breakOnMain", sp.breakOnMain);
hjk's avatar
hjk committed
323
    cmd.arg("useTerminal", sp.useTerminal);
324
    cmd.arg("startMode", sp.startMode);
hjk's avatar
hjk committed
325

326 327 328 329 330 331
    cmd.beginList("bkpts");
    foreach (Breakpoint bp, breakHandler()->unclaimedBreakpoints()) {
        if (acceptsBreakpoint(bp)) {
            showMessage(_("TAKING OWNERSHIP OF BREAKPOINT %1 IN STATE %2")
                            .arg(bp.id().toString()).arg(bp.state()));
            bp.setEngine(this);
332
            bp.notifyBreakpointInsertProceeding();
333
            cmd.beginGroup();
334
            bp.addToCommand(&cmd);
335 336 337 338 339 340 341
            cmd.endGroup();
        } else {
            showMessage(_("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE")
                .arg(bp.id().toString()).arg(bp.state()));
        }
    }
    cmd.endList();
342

343
    cmd.beginList("processArgs");
344
    foreach (const QString &arg, args.toUnixArgs())
345 346
        cmd.arg(arg.toUtf8().toHex());
    cmd.endList();
347

hjk's avatar
hjk committed
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
    if (sp.useTerminal) {
        QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
        const qint64 attachedPID = m_stubProc.applicationPID();
        const qint64 attachedMainThreadID = m_stubProc.applicationMainThreadID();
        const QString msg = (attachedMainThreadID != -1)
                ? QString::fromLatin1("Attaching to %1 (%2)").arg(attachedPID).arg(attachedMainThreadID)
                : QString::fromLatin1("Attaching to %1").arg(attachedPID);
        showMessage(msg, LogMisc);
        cmd.arg("attachPid", attachedPID);

    } else {

        cmd.arg("startMode", sp.startMode);
        // it is better not to check the start mode on the python sid (as we would have to duplicate the
        // enum values), and thus we assume that if the sp.attachPID is valid we really have to attach
        QTC_CHECK(sp.attachPID <= 0 || (sp.startMode == AttachCrashedExternal
                                    || sp.startMode == AttachExternal));
        cmd.arg("attachPid", sp.attachPID);
        cmd.arg("sysRoot", sp.deviceSymbolsRoot.isEmpty() ? sp.sysRoot : sp.deviceSymbolsRoot);
        cmd.arg("remoteChannel", ((sp.startMode == AttachToRemoteProcess
                                   || sp.startMode == AttachToRemoteServer)
                                  ? sp.remoteChannel : QString()));
        cmd.arg("platform", sp.platform);
        QTC_CHECK(!sp.continueAfterAttach || (sp.startMode == AttachToRemoteProcess
                                              || sp.startMode == AttachExternal
                                              || sp.startMode == AttachToRemoteServer));
        m_continueAtNextSpontaneousStop = false;
    }

377
    runCommand(cmd);
378 379 380 381
}

void LldbEngine::runEngine()
{
382
    const DebuggerStartParameters &sp = startParameters();
383
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state(); return);
384
    showStatusMessage(tr("Running requested..."), 5000);
385 386 387 388 389 390
    DebuggerCommand cmd("runEngine");
    if (sp.startMode == AttachCore) {
        cmd.arg("coreFile", sp.coreFile);
        cmd.arg("continuation", "updateAll");
    }
    runCommand(cmd);
391 392 393 394 395
}

void LldbEngine::interruptInferior()
{
    showStatusMessage(tr("Interrupt requested..."), 5000);
396
    runCommand("interruptInferior");
397 398
}

399 400 401 402
void LldbEngine::executeStep()
{
    resetLocation();
    notifyInferiorRunRequested();
403
    runCommand("executeStep");
404 405
}

406 407 408 409
void LldbEngine::executeStepI()
{
    resetLocation();
    notifyInferiorRunRequested();
410
    runCommand("executeStepI");
411 412 413 414 415 416
}

void LldbEngine::executeStepOut()
{
    resetLocation();
    notifyInferiorRunRequested();
417
    runCommand("executeStepOut");
418 419 420 421 422 423
}

void LldbEngine::executeNext()
{
    resetLocation();
    notifyInferiorRunRequested();
424
    runCommand("executeNext");
425 426 427 428 429 430
}

void LldbEngine::executeNextI()
{
    resetLocation();
    notifyInferiorRunRequested();
431
    runCommand("executeNextI");
432 433 434 435 436 437
}

void LldbEngine::continueInferior()
{
    resetLocation();
    notifyInferiorRunRequested();
438
    runCommand("continueInferior");
439 440
}

441
void LldbEngine::handleResponse(const QByteArray &response)
442
{
443 444
    GdbMi all;
    all.fromStringMultiple(response);
445

446 447 448 449
    foreach (const GdbMi &item, all.children()) {
        const QByteArray name = item.name();
        if (name == "data")
            refreshLocals(item);
450
        else if (name == "dumpers") {
hjk's avatar
hjk committed
451
            watchHandler()->addDumpers(item);
452 453
            setupInferiorStage2();
        } else if (name == "stack")
454 455 456 457 458 459 460 461 462 463 464 465 466
            refreshStack(item);
        else if (name == "registers")
            refreshRegisters(item);
        else if (name == "threads")
            refreshThreads(item);
        else if (name == "typeinfo")
            refreshTypeInfo(item);
        else if (name == "state")
            refreshState(item);
        else if (name == "location")
            refreshLocation(item);
        else if (name == "modules")
            refreshModules(item);
467 468
        else if (name == "symbols")
            refreshSymbols(item);
469 470 471 472 473 474
        else if (name == "breakpoint-added")
            refreshAddedBreakpoint(item);
        else if (name == "breakpoint-changed")
            refreshChangedBreakpoint(item);
        else if (name == "breakpoint-removed")
            refreshRemovedBreakpoint(item);
475 476
        else if (name == "output")
            refreshOutput(item);
477 478
        else if (name == "disassembly")
            refreshDisassembly(item);
479 480
        else if (name == "memory")
            refreshMemory(item);
481 482
        else if (name == "full-backtrace")
            showFullBacktrace(item);
483 484
        else if (name == "continuation")
            handleContinuation(item);
hjk's avatar
hjk committed
485 486 487 488 489 490
        else if (name == "statusmessage") {
            QString msg = QString::fromUtf8(item.data());
            if (msg.size())
                msg[0] = msg.at(0).toUpper();
            showStatusMessage(msg);
        }
491 492 493
    }
}

494 495 496 497
void LldbEngine::handleContinuation(const GdbMi &data)
{
    if (data.data() == "updateLocals") {
        updateLocals();
498 499 500 501
    } else if (data.data() == "updateAll") {
        updateAll();
    } else {
        QTC_ASSERT(false, qDebug() << "Unknown continuation: " << data.data());
502 503 504
    }
}

505 506
void LldbEngine::showFullBacktrace(const GdbMi &data)
{
507
    Internal::openTextEditor(_("Backtrace $"),
508 509 510
        QString::fromUtf8(QByteArray::fromHex(data.data())));
}

511 512
void LldbEngine::executeRunToLine(const ContextData &data)
{
513 514
    resetLocation();
    notifyInferiorRunRequested();
515
    DebuggerCommand cmd("executeRunToLocation");
hjk's avatar
hjk committed
516 517 518 519
    cmd.arg("file", data.fileName);
    cmd.arg("line", data.lineNumber);
    cmd.arg("address", data.address);
    runCommand(cmd);
520 521 522 523
}

void LldbEngine::executeRunToFunction(const QString &functionName)
{
524 525
    resetLocation();
    notifyInferiorRunRequested();
526 527 528
    DebuggerCommand cmd("executeRunToFunction");
    cmd.arg("function", functionName);
    runCommand(cmd);
529 530 531 532
}

void LldbEngine::executeJumpToLine(const ContextData &data)
{
533
    resetLocation();
534
    DebuggerCommand cmd("executeJumpToLocation");
535 536 537 538
    cmd.arg("file", data.fileName);
    cmd.arg("line", data.lineNumber);
    cmd.arg("address", data.address);
    runCommand(cmd);
539 540 541 542 543 544 545
}

void LldbEngine::activateFrame(int frameIndex)
{
    if (state() != InferiorStopOk && state() != InferiorUnrunnable)
        return;

546 547 548
    StackHandler *handler = stackHandler();

    const int n = handler->stackSize();
549
    if (frameIndex == n) {
550
        DebuggerCommand cmd("reportStack");
551
        cmd.arg("nativeMixed", isNativeMixedActive());
552 553 554 555
        cmd.arg("stacklimit", n * 10 + 3);
        runCommand(cmd);
        return;
    }
556

557 558 559 560
    QTC_ASSERT(frameIndex < handler->stackSize(), return);
    handler->setCurrentIndex(frameIndex);
    gotoLocation(handler->currentFrame());

561
    DebuggerCommand cmd("activateFrame");
562 563
    cmd.arg("index", frameIndex);
    cmd.arg("thread", threadsHandler()->currentThread().raw());
564
    cmd.arg("continuation", "updateLocals");
565
    runCommand(cmd);
566 567 568 569
}

void LldbEngine::selectThread(ThreadId threadId)
{
570 571 572
    DebuggerCommand cmd("selectThread");
    cmd.arg("id", threadId.raw());
    runCommand(cmd);
573
    updateAll();
574 575
}

576
bool LldbEngine::stateAcceptsBreakpointChanges() const
577
{
578 579 580 581 582 583 584 585 586 587
    switch (state()) {
    case InferiorSetupRequested:
    case InferiorRunRequested:
    case InferiorRunOk:
    case InferiorStopRequested:
    case InferiorStopOk:
        return true;
    default:
        return false;
    }
588 589
}

590
bool LldbEngine::acceptsBreakpoint(Breakpoint bp) const
591
{
592 593 594 595 596 597 598
    if (startParameters().startMode == AttachCore)
        return false;
    // We handle QML breakpoint unless specifically disabled.
    if (isNativeMixedEnabled() && !(startParameters().languages & QmlLanguage))
        return true;
    return bp.parameters().isCppBreakpoint();
}
599

600 601 602
void LldbEngine::insertBreakpoint(Breakpoint bp)
{
    DebuggerCommand cmd("insertBreakpoint");
603
    bp.addToCommand(&cmd);
604
    bp.notifyBreakpointInsertProceeding();
605
    runCommand(cmd);
606 607
}

608
void LldbEngine::changeBreakpoint(Breakpoint bp)
609
{
610 611
    const BreakpointResponse &response = bp.response();
    DebuggerCommand cmd("changeBreakpoint");
612
    cmd.arg("lldbid", response.id.toByteArray());
613
    bp.addToCommand(&cmd);
614 615 616
    bp.notifyBreakpointChangeProceeding();
    runCommand(cmd);
}
617

618 619 620 621 622 623 624 625
void LldbEngine::removeBreakpoint(Breakpoint bp)
{
    const BreakpointResponse &response = bp.response();
    DebuggerCommand cmd("removeBreakpoint");
    cmd.arg("modelid", bp.id().toByteArray());
    cmd.arg("lldbid", response.id.toByteArray());
    bp.notifyBreakpointRemoveProceeding();
    runCommand(cmd);
626
}
627

628
void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added)
629 630
{
    BreakHandler *handler = breakHandler();
631
    BreakpointResponseId rid = BreakpointResponseId(bkpt["lldbid"].data());
632
    BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
633 634 635 636
    Breakpoint bp = handler->breakpointById(id);
    if (!bp.isValid())
        bp = handler->findBreakpointByResponseId(rid);
    BreakpointResponse response = bp.response();
637 638 639 640
    if (added)
        response.id = rid;
    QTC_CHECK(response.id == rid);
    response.address = 0;
641 642
    response.enabled = bkpt["enabled"].toInt();
    response.ignoreCount = bkpt["ignorecount"].toInt();
643
    response.condition = QByteArray::fromHex(bkpt["condition"].data());
644
    response.hitCount = bkpt["hitcount"].toInt();
645 646 647 648
    response.fileName = bkpt["file"].toUtf8();
    response.lineNumber = bkpt["line"].toInt();

    GdbMi locations = bkpt["locations"];
649
    const int numChild = int(locations.children().size());
650 651 652 653 654 655 656 657 658 659
    if (numChild > 1) {
        foreach (const GdbMi &location, locations.children()) {
            const int locid = location["locid"].toInt();
            BreakpointResponse sub;
            sub.id = BreakpointResponseId(rid.majorPart(), locid);
            sub.type = response.type;
            sub.address = location["addr"].toAddress();
            sub.functionName = location["func"].toUtf8();
            sub.fileName = location["file"].toUtf8();
            sub.lineNumber = location["line"].toInt();
660
            bp.insertSubBreakpoint(sub);
661
        }
662 663 664 665
    } else if (numChild == 1) {
        const GdbMi location = locations.childAt(0);
        response.address = location["addr"].toAddress();
        response.functionName = location["func"].toUtf8();
666
    } else {
667 668
        // This can happen for pending breakpoints.
        showMessage(_("NO LOCATIONS (YET) FOR BP %1").arg(response.toString()));
669
    }
670
    bp.setResponse(response);
671
    if (added)
672
        bp.notifyBreakpointInsertOk();
673
    else
674
        bp.notifyBreakpointChangeOk();
675 676
}

677
void LldbEngine::refreshDisassembly(const GdbMi &data)
678 679 680
{
    DisassemblerLines result;

681
    int cookie = data["cookie"].toInt();
682 683 684 685
    QPointer<DisassemblerAgent> agent = m_disassemblerAgents.key(cookie);
    if (!agent.isNull()) {
        foreach (const GdbMi &line, data["lines"].children()) {
            DisassemblerLine dl;
686
            dl.address = line["address"].toAddress();
687 688
            dl.data = line["inst"].toUtf8();
            dl.function = line["func-name"].toUtf8();
689
            dl.offset = line["offset"].toInt();
690 691 692
            QByteArray comment = line["comment"].data();
            if (!comment.isEmpty())
                dl.data += QString::fromUtf8(" # " + comment);
693 694 695
            result.appendLine(dl);
        }
        agent->setContents(result);
696
    }
697
}
698

699 700
void LldbEngine::refreshMemory(const GdbMi &data)
{
701
    int cookie = data["cookie"].toInt();
702
    qulonglong addr = data["address"].toAddress();
703 704 705 706 707 708 709
    QPointer<MemoryAgent> agent = m_memoryAgents.key(cookie);
    if (!agent.isNull()) {
        QPointer<QObject> token = m_memoryAgentTokens.value(cookie);
        QTC_ASSERT(!token.isNull(), return);
        QByteArray ba = QByteArray::fromHex(data["contents"].data());
        agent->addLazyData(token.data(), addr, ba);
    }
710 711
}

712 713 714 715 716 717 718 719 720 721 722 723
void LldbEngine::refreshOutput(const GdbMi &output)
{
    QByteArray channel = output["channel"].data();
    QByteArray data = QByteArray::fromHex(output["data"].data());
    LogChannel ch = AppStuff;
    if (channel == "stdout")
        ch = AppOutput;
    else if (channel == "stderr")
        ch = AppError;
    showMessage(QString::fromUtf8(data), ch);
}

724 725 726
void LldbEngine::refreshAddedBreakpoint(const GdbMi &bkpt)
{
    BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
727 728
    Breakpoint bp = breakHandler()->breakpointById(id);
    QTC_CHECK(bp.state() == BreakpointInsertProceeding);
729 730 731 732 733 734
    updateBreakpointData(bkpt, true);
}

void LldbEngine::refreshChangedBreakpoint(const GdbMi &bkpt)
{
    BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
735 736
    Breakpoint bp = breakHandler()->breakpointById(id);
    QTC_CHECK(!bp.isValid() || bp.state() == BreakpointChangeProceeding);
737 738 739 740
    updateBreakpointData(bkpt, false);
}

void LldbEngine::refreshRemovedBreakpoint(const GdbMi &bkpt)
741
{
742
    BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
743 744 745
    Breakpoint bp = breakHandler()->breakpointById(id);
    QTC_CHECK(bp.state() == BreakpointRemoveProceeding);
    bp.notifyBreakpointRemoveOk();
746 747 748 749 750 751 752 753 754 755 756 757 758
}

void LldbEngine::loadSymbols(const QString &moduleName)
{
    Q_UNUSED(moduleName)
}

void LldbEngine::loadAllSymbols()
{
}

void LldbEngine::reloadModules()
{
759
    runCommand("listModules");
760 761
}

762
void LldbEngine::refreshModules(const GdbMi &modules)
763
{
764 765
    ModulesHandler *handler = modulesHandler();
    handler->beginUpdateAll();
766
    foreach (const GdbMi &item, modules.children()) {
767
        Module module;
768 769
        module.modulePath = item["file"].toUtf8();
        module.moduleName = item["name"].toUtf8();
770
        module.symbolsRead = Module::UnknownReadState;
771
        module.startAddress = item["loaded_addr"].toAddress();
772
        module.endAddress = 0; // FIXME: End address not easily available.
773
        handler->updateModule(module);
774
    }
775
    handler->endUpdateAll();
776 777 778 779
}

void LldbEngine::requestModuleSymbols(const QString &moduleName)
{
780 781 782
    DebuggerCommand cmd("listSymbols");
    cmd.arg("module", moduleName);
    runCommand(cmd);
783 784
}

785
void LldbEngine::refreshSymbols(const GdbMi &symbols)
786
{
787
    QString moduleName = symbols["module"].toUtf8();
788 789 790
    Symbols syms;
    foreach (const GdbMi &item, symbols["symbols"].children()) {
        Symbol symbol;
791 792 793 794 795
        symbol.address = item["address"].toUtf8();
        symbol.name = item["name"].toUtf8();
        symbol.state = item["state"].toUtf8();
        symbol.section = item["section"].toUtf8();
        symbol.demangled = item["demangled"].toUtf8();
796 797
        syms.append(symbol);
    }
798
   Internal::showModuleSymbols(moduleName, syms);
799 800
}

801

802 803 804 805 806 807
//////////////////////////////////////////////////////////////////////
//
// Tooltip specific stuff
//
//////////////////////////////////////////////////////////////////////

808
bool LldbEngine::setToolTipExpression(const DebuggerToolTipContext &context)
809
{
810
    if (state() != InferiorStopOk || !context.isCppEditor) {
811 812
        //qDebug() << "SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED "
        // " OR NOT A CPPEDITOR";
813 814 815
        return false;
    }

816 817
    UpdateParameters params;
    params.tryPartial = true;
818
    params.varList = context.iname;
819 820 821
    doUpdateLocals(params);

    return true;
822 823
}

824 825
void LldbEngine::updateAll()
{
826
    DebuggerCommand cmd("reportStack");
827
    cmd.arg("nativeMixed", isNativeMixedActive());
828 829
    cmd.arg("stacklimit", action(MaximalStackDepth)->value().toInt());
    cmd.arg("continuation", "updateLocals");
830 831 832
    runCommand(cmd);
}

833
void LldbEngine::reloadFullStack()
834
{
835
    DebuggerCommand cmd("reportStack");
836
    cmd.arg("nativeMixed", isNativeMixedActive());
837
    cmd.arg("stacklimit", -1);
838 839 840
    runCommand(cmd);
}

841 842 843 844 845 846
//////////////////////////////////////////////////////////////////////
//
// Watch specific stuff
//
//////////////////////////////////////////////////////////////////////

847
void LldbEngine::assignValueInDebugger(WatchItem *,
848
    const QString &expression, const QVariant &value)
849
{
850
    DebuggerCommand cmd("assignValue");
851 852 853
    cmd.arg("exp", expression.toLatin1().toHex());
    cmd.arg("value", value.toString().toLatin1().toHex());
    runCommand(cmd);
854 855
}

856
void LldbEngine::updateWatchItem(WatchItem *)
857
{
858 859 860 861
    updateLocals();
}

void LldbEngine::updateLocals()
862 863 864 865 866 867
{
    UpdateParameters params;
    doUpdateLocals(params);
}

void LldbEngine::doUpdateLocals(UpdateParameters params)
868
{
869 870 871 872 873
    if (stackHandler()->stackSize() == 0) {
        showMessage(_("SKIPPING LOCALS DUE TO EMPTY STACK"));
        return;
    }

874
    DebuggerCommand cmd("updateData");
875
    cmd.arg("nativeMixed", isNativeMixedActive());
876
    watchHandler()->appendFormatRequests(&cmd);
877 878

    const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty();
hjk's avatar
hjk committed
879
    cmd.arg("passexceptions", alwaysVerbose);
hjk's avatar
hjk committed
880 881 882
    cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
    cmd.arg("autoderef", boolSetting(AutoDerefPointers));
    cmd.arg("dyntype", boolSetting(UseDynamicType));
883
    cmd.arg("partial", params.tryPartial);
hjk's avatar
hjk committed
884 885

    cmd.beginList("watchers");
hjk's avatar
hjk committed
886

887
    // Watchers
hjk's avatar
hjk committed
888 889 890
    QHashIterator<QByteArray, int> it(WatchHandler::watcherNames());
    while (it.hasNext()) {
        it.next();
891 892 893 894
        cmd.beginGroup();
        cmd.arg("iname", "watch." + QByteArray::number(it.value()));
        cmd.arg("exp", it.key().toHex());
        cmd.endGroup();
895
    }
hjk's avatar
hjk committed
896 897 898 899

    // Tooltips
    DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this);
    foreach (const DebuggerToolTipContext &p, toolTips) {
900 901 902 903
        cmd.beginGroup();
        cmd.arg("iname", p.iname);
        cmd.arg("exp", p.expression.toLatin1().toHex());
        cmd.endGroup();
hjk's avatar
hjk committed
904
    }
hjk's avatar
hjk committed
905

hjk's avatar
hjk committed
906 907
    cmd.endList();

908 909
    //cmd.arg("resultvarname", m_resultVarName);

910 911 912
    m_lastDebuggableCommand = cmd;
    m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1");

913
    watchHandler()->notifyUpdateStarted();
914
    runCommand(cmd);
915 916

    reloadRegisters();
917 918 919 920
}

void LldbEngine::handleLldbError(QProcess::ProcessError error)
{
921
    showMessage(_("LLDB PROCESS ERROR: %1").arg(error));
922 923 924 925 926 927 928 929 930 931
    switch (error) {
    case QProcess::Crashed:
        break; // will get a processExited() as well
    // impossible case QProcess::FailedToStart:
    case QProcess::ReadError:
    case QProcess::WriteError:
    case QProcess::Timedout:
    default:
        //setState(EngineShutdownRequested, true);
        m_lldbProc.kill();
hjk's avatar
hjk committed
932
        AsynchronousMessageBox::critical(tr("LLDB I/O Error"), errorMessage(error));
933 934 935 936 937 938 939 940
        break;
    }
}

QString LldbEngine::errorMessage(QProcess::ProcessError error) const
{
    switch (error) {
        case QProcess::FailedToStart:
Leena Miettinen's avatar
Leena Miettinen committed
941
            return tr("The LLDB process failed to start. Either the "
942
                "invoked program \"%1\" is missing, or you may have insufficient "
943
                "permissions to invoke the program.")
944
                .arg(m_lldbCmd);
945
        case QProcess::Crashed:
Leena Miettinen's avatar
Leena Miettinen committed
946