lldbengine.cpp 39.2 KB
Newer Older
1 2
/****************************************************************************
**
3 4
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://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
12 13 14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
15
**
16 17 18 19 20 21 22
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 24 25 26 27
**
****************************************************************************/

#include "lldbengine.h"

28 29 30
#include <debugger/debuggeractions.h>
#include <debugger/debuggercore.h>
#include <debugger/debuggerdialogs.h>
Fawzi Mohamed's avatar
Fawzi Mohamed committed
31
#include <debugger/debuggerinternalconstants.h>
32
#include <debugger/debuggermainwindow.h>
33 34 35
#include <debugger/debuggerprotocol.h>
#include <debugger/debuggerstartparameters.h>
#include <debugger/debuggertooltipmanager.h>
36

37 38 39 40 41 42 43 44 45
#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>
46

47
#include <coreplugin/messagebox.h>
48 49 50
#include <coreplugin/idocument.h>
#include <coreplugin/icore.h>

hjk's avatar
hjk committed
51 52 53 54 55
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
#include <utils/qtcprocess.h>

#include <QApplication>
56 57 58 59 60 61
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QTimer>
#include <QToolTip>
hjk's avatar
hjk committed
62
#include <QVariant>
63
#include <QJsonArray>
64
#include <QRegularExpression>
65

hjk's avatar
hjk committed
66
using namespace Core;
hjk's avatar
hjk committed
67 68
using namespace Utils;

69 70 71
namespace Debugger {
namespace Internal {

72 73 74 75 76 77
static int &currentToken()
{
    static int token = 0;
    return token;
}

78 79 80 81 82 83
///////////////////////////////////////////////////////////////////////
//
// LldbEngine
//
///////////////////////////////////////////////////////////////////////

84
LldbEngine::LldbEngine(const DebuggerRunParameters &startParameters)
85
    : DebuggerEngine(startParameters), m_continueAtNextSpontaneousStop(false)
86
{
87
    m_lastAgentId = 0;
88
    setObjectName(QLatin1String("LldbEngine"));
89

hjk's avatar
hjk committed
90 91 92
    connect(action(AutoDerefPointers), &SavedAction::valueChanged,
            this, &LldbEngine::updateLocals);
    connect(action(CreateFullBacktrace), &QAction::triggered,
93
            this, &LldbEngine::fetchFullBacktrace);
hjk's avatar
hjk committed
94 95 96 97 98 99
    connect(action(UseDebuggingHelpers), &SavedAction::valueChanged,
            this, &LldbEngine::updateLocals);
    connect(action(UseDynamicType), &SavedAction::valueChanged,
            this, &LldbEngine::updateLocals);
    connect(action(IntelFlavor), &SavedAction::valueChanged,
            this, &LldbEngine::updateAll);
100 101 102
}

LldbEngine::~LldbEngine()
hjk's avatar
hjk committed
103 104
{
    m_stubProc.disconnect(); // Avoid spurious state transitions from late exiting stub
105
    m_lldbProc.disconnect();
hjk's avatar
hjk committed
106 107
}

hjk's avatar
hjk committed
108
void LldbEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages)
109
{
110 111 112
    DebuggerCommand cmd("executeDebuggerCommand");
    cmd.arg("command", command);
    runCommand(cmd);
113 114
}

115
void LldbEngine::runCommand(const DebuggerCommand &cmd)
116
{
117 118 119
    if (m_lldbProc.state() != QProcess::Running) {
        // This can legally happen e.g. through a reloadModule()
        // triggered by changes in view visibility.
hjk's avatar
hjk committed
120 121
        showMessage(QString("NO LLDB PROCESS RUNNING, CMD IGNORED: %1 %2")
            .arg(cmd.function).arg(state()));
122 123
        return;
    }
124
    const int tok = ++currentToken();
125
    DebuggerCommand command = cmd;
126
    command.arg("token", tok);
Erik Verbruggen's avatar
Erik Verbruggen committed
127
    QString token = QString::number(tok);
hjk's avatar
hjk committed
128
    QString function = command.function + "(" + command.argsToPython() + ")";
129 130 131 132
    QString msg = token + function + '\n';
    if (cmd.flags == LldbEngine::Silent)
        msg.replace(QRegularExpression("\"environment\":.[^]]*."), "<environment suppressed>");
    showMessage(msg, LogInput);
133
    m_commandForToken[currentToken()] = command;
hjk's avatar
hjk committed
134
    m_lldbProc.write("script theDumper." + function.toUtf8() + "\n");
135 136
}

137 138 139 140 141
void LldbEngine::debugLastCommand()
{
    runCommand(m_lastDebuggableCommand);
}

142 143 144
void LldbEngine::shutdownInferior()
{
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
145
    runCommand({"shutdownInferior"});
146 147 148 149 150 151
}

void LldbEngine::shutdownEngine()
{
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
    m_lldbProc.kill();
152
    if (runParameters().useTerminal)
hjk's avatar
hjk committed
153
        m_stubProc.stop();
154
    notifyEngineShutdownOk();
155 156
}

157 158 159 160
void LldbEngine::abortDebugger()
{
    if (targetState() == DebuggerFinished) {
        // We already tried. Try harder.
hjk's avatar
hjk committed
161
        showMessage("ABORTING DEBUGGER. SECOND TIME.");
162 163 164
        m_lldbProc.kill();
    } else {
        // Be friendly the first time. This will change targetState().
hjk's avatar
hjk committed
165
        showMessage("ABORTING DEBUGGER. FIRST TIME.");
166 167 168 169
        quitDebugger();
    }
}

hjk's avatar
hjk committed
170 171 172 173
// FIXME: Merge with GdbEngine/QtcProcess
bool LldbEngine::prepareCommand()
{
    if (HostOsInfo::isWindowsHost()) {
174
        DebuggerRunParameters &rp = runParameters();
hjk's avatar
hjk committed
175
        QtcProcess::SplitError perr;
176 177 178
        rp.inferior.commandLineArguments
                = QtcProcess::prepareArgs(rp.inferior.commandLineArguments, &perr, HostOsInfo::hostOs(),
                                          nullptr, &rp.inferior.workingDirectory).toWindowsArgs();
hjk's avatar
hjk committed
179
        if (perr != QtcProcess::SplitOk) {
hjk's avatar
hjk committed
180 181 182 183 184 185 186 187 188
            // perr == BadQuoting is never returned on Windows
            // FIXME? QTCREATORBUG-2809
            notifyEngineSetupFailed();
            return false;
        }
    }
    return true;
}

189 190
void LldbEngine::setupEngine()
{
191
    // FIXME: We can't handle terminals yet.
192
    if (runParameters().useTerminal) {
193
        qWarning("Run in Terminal is not supported yet with the LLDB backend");
194
        showMessage(tr("Run in Terminal is not supported with the LLDB backend."), AppError);
195 196 197
        runParameters().useTerminal = false;
    }

198
    if (runParameters().useTerminal) {
199
        QTC_CHECK(false); // See above.
200
        if (HostOsInfo::isWindowsHost()) {
201 202 203 204 205
            // Windows up to xp needs a workaround for attaching to freshly started processes. see proc_stub_win
            if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
                m_stubProc.setMode(ConsoleProcess::Suspend);
            else
                m_stubProc.setMode(ConsoleProcess::Debug);
206
        } else {
207 208
            m_stubProc.setMode(ConsoleProcess::Debug);
            m_stubProc.setSettings(ICore::settings());
209
        }
210

hjk's avatar
hjk committed
211
        QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
hjk's avatar
hjk committed
212
        showMessage("TRYING TO START ADAPTER");
hjk's avatar
hjk committed
213 214 215 216 217 218 219 220 221 222 223 224

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

225
        m_stubProc.setWorkingDirectory(runParameters().inferior.workingDirectory);
hjk's avatar
hjk committed
226
        // Set environment + dumper preload.
227
        m_stubProc.setEnvironment(runParameters().stubEnvironment);
hjk's avatar
hjk committed
228

hjk's avatar
hjk committed
229 230 231
        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
232 233 234
        // FIXME: Starting the stub implies starting the inferior. This is
        // fairly unclean as far as the state machine and error reporting go.

235 236
        if (!m_stubProc.start(runParameters().inferior.executable,
                             runParameters().inferior.commandLineArguments)) {
hjk's avatar
hjk committed
237 238 239 240 241 242 243 244
            // Error message for user is delivered via a signal.
            //handleAdapterStartFailed(QString());
            notifyEngineSetupFailed();
            return;
        }

    } else {
        QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
245
        if (runParameters().remoteSetupNeeded)
hjk's avatar
hjk committed
246 247 248 249
            notifyEngineRequestRemoteSetup();
        else
            startLldb();
    }
Fawzi Mohamed's avatar
Fawzi Mohamed committed
250
}
251

Fawzi Mohamed's avatar
Fawzi Mohamed committed
252 253
void LldbEngine::startLldb()
{
254
    QString lldbCmd = runParameters().debugger.executable;
255
    connect(&m_lldbProc, &QProcess::errorOccurred, this, &LldbEngine::handleLldbError);
hjk's avatar
hjk committed
256 257 258 259 260 261 262 263 264
    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);
265

266 267 268 269
    showMessage("STARTING LLDB: " + lldbCmd);
    m_lldbProc.setEnvironment(runParameters().debugger.environment);
    if (QFileInfo(runParameters().debugger.workingDirectory).isDir())
        m_lldbProc.setWorkingDirectory(runParameters().debugger.workingDirectory);
270

271
    m_lldbProc.setCommand(lldbCmd, QString());
272
    m_lldbProc.start();
273 274

    if (!m_lldbProc.waitForStarted()) {
275
        const QString msg = tr("Unable to start LLDB \"%1\": %2")
276
            .arg(lldbCmd, m_lldbProc.errorString());
277
        notifyEngineSetupFailed();
hjk's avatar
hjk committed
278
        showMessage("ADAPTER START FAILED");
279
        if (!msg.isEmpty())
hjk's avatar
hjk committed
280
            ICore::showWarningWithOptions(tr("Adapter start failed."), msg);
281
        return;
282
    }
283 284 285
    m_lldbProc.waitForReadyRead(1000);
    m_lldbProc.write("sc print('@\\nlldbstartupok@\\n')\n");
}
286

287 288 289
// FIXME: splitting of startLldb() necessary to support LLDB <= 310 - revert asap
void LldbEngine::startLldbStage2()
{
hjk's avatar
hjk committed
290
    showMessage("ADAPTER STARTED");
291 292 293 294 295
    showStatusMessage(tr("Setting up inferior..."));

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

hjk's avatar
hjk committed
296 297 298 299
    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")
300

301
    const QString commands = expand(stringSetting(GdbStartupCommands));
302
    if (!commands.isEmpty())
303
        m_lldbProc.write(commands.toLocal8Bit() + '\n');
304 305 306 307
}

void LldbEngine::setupInferior()
{
hjk's avatar
hjk committed
308
    const QString path = stringSetting(ExtraDumperFile);
309
    if (!path.isEmpty() && QFileInfo(path).isReadable()) {
310
        DebuggerCommand cmd("addDumperModule");
hjk's avatar
hjk committed
311
        cmd.arg("path", path);
312
        runCommand(cmd);
313 314
    }

hjk's avatar
hjk committed
315
    const QString commands = stringSetting(ExtraDumperCommands);
316
    if (!commands.isEmpty()) {
317
        DebuggerCommand cmd("executeDebuggerCommand");
hjk's avatar
hjk committed
318
        cmd.arg("command", commands);
319 320 321
        runCommand(cmd);
    }

322
    DebuggerCommand cmd1("loadDumpers");
323
    cmd1.callback = [this](const DebuggerResponse &response) {
324
        watchHandler()->addDumpers(response.data["dumpers"]);
325
    };
hjk's avatar
hjk committed
326
    runCommand(cmd1);
327

328
    const DebuggerRunParameters &rp = runParameters();
hjk's avatar
hjk committed
329

330
    QString executable;
hjk's avatar
hjk committed
331
    QtcProcess::Arguments args;
332 333
    QtcProcess::prepareCommand(QFileInfo(rp.inferior.executable).absoluteFilePath(),
                               rp.inferior.commandLineArguments, &executable, &args);
334

335 336
    DebuggerCommand cmd2("setupInferior");
    cmd2.arg("executable", executable);
337 338 339
    cmd2.arg("breakonmain", rp.breakOnMain);
    cmd2.arg("useterminal", rp.useTerminal);
    cmd2.arg("startmode", rp.startMode);
340
    cmd2.arg("nativemixed", isNativeMixedActive());
341
    cmd2.arg("workingdirectory", rp.inferior.workingDirectory);
342

343 344 345 346 347
    QJsonArray env;
    foreach (const QString &item, rp.inferior.environment.toStringList())
        env.append(toHex(item));
    cmd2.arg("environment", env);

348
    QJsonArray processArgs;
349
    foreach (const QString &arg, args.toUnixArgs())
350
        processArgs.append(QLatin1String(arg.toUtf8().toHex()));
351
    cmd2.arg("processargs", processArgs);
352

353
    if (rp.useTerminal) {
hjk's avatar
hjk committed
354 355 356 357 358 359 360
        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);
361
        cmd2.arg("attachpid", attachedPID);
hjk's avatar
hjk committed
362 363 364

    } else {

365
        cmd2.arg("startmode", rp.startMode);
hjk's avatar
hjk committed
366
        // it is better not to check the start mode on the python sid (as we would have to duplicate the
367 368 369
        // enum values), and thus we assume that if the rp.attachPID is valid we really have to attach
        QTC_CHECK(rp.attachPID <= 0 || (rp.startMode == AttachCrashedExternal
                                    || rp.startMode == AttachExternal));
370 371 372
        cmd2.arg("attachpid", rp.attachPID);
        cmd2.arg("sysroot", rp.deviceSymbolsRoot.isEmpty() ? rp.sysRoot : rp.deviceSymbolsRoot);
        cmd2.arg("remotechannel", ((rp.startMode == AttachToRemoteProcess
373 374
                                   || rp.startMode == AttachToRemoteServer)
                                  ? rp.remoteChannel : QString()));
375
        cmd2.arg("platform", rp.platform);
376 377 378
        QTC_CHECK(!rp.continueAfterAttach || (rp.startMode == AttachToRemoteProcess
                                              || rp.startMode == AttachExternal
                                              || rp.startMode == AttachToRemoteServer));
hjk's avatar
hjk committed
379 380 381
        m_continueAtNextSpontaneousStop = false;
    }

382 383 384 385 386 387 388 389
    cmd2.callback = [this](const DebuggerResponse &response) {
        bool success = response.data["success"].toInt();
        if (success) {
            foreach (Breakpoint bp, breakHandler()->unclaimedBreakpoints()) {
                if (acceptsBreakpoint(bp)) {
                    bp.setEngine(this);
                    insertBreakpoint(bp);
                } else {
hjk's avatar
hjk committed
390
                    showMessage(QString("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE")
391 392 393 394 395 396 397 398
                                .arg(bp.id().toString()).arg(bp.state()));
                }
            }
            notifyInferiorSetupOk();
        } else {
            notifyInferiorSetupFailed();
        }
    };
399 400

    cmd2.flags = LldbEngine::Silent;
401
    runCommand(cmd2);
402 403 404 405
}

void LldbEngine::runEngine()
{
406
    const DebuggerRunParameters &rp = runParameters();
407
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state(); return);
408
    showStatusMessage(tr("Running requested..."), 5000);
409
    DebuggerCommand cmd("runEngine");
410
    if (rp.startMode == AttachCore)
411
        cmd.arg("coreFile", rp.coreFile);
412
    runCommand(cmd);
413 414 415 416 417
}

void LldbEngine::interruptInferior()
{
    showStatusMessage(tr("Interrupt requested..."), 5000);
418
    runCommand({"interruptInferior"});
419 420
}

421 422 423
void LldbEngine::executeStep()
{
    notifyInferiorRunRequested();
424
    runCommand({"executeStep"});
425 426
}

427 428 429
void LldbEngine::executeStepI()
{
    notifyInferiorRunRequested();
430
    runCommand({"executeStepI"});
431 432 433 434 435
}

void LldbEngine::executeStepOut()
{
    notifyInferiorRunRequested();
436
    runCommand({"executeStepOut"});
437 438 439 440 441
}

void LldbEngine::executeNext()
{
    notifyInferiorRunRequested();
442
    runCommand({"executeNext"});
443 444 445 446 447
}

void LldbEngine::executeNextI()
{
    notifyInferiorRunRequested();
448
    runCommand({"executeNextI"});
449 450 451 452 453
}

void LldbEngine::continueInferior()
{
    notifyInferiorRunRequested();
454 455 456 457 458 459
    DebuggerCommand cmd("continueInferior");
    cmd.callback = [this](const DebuggerResponse &response) {
        if (response.resultClass == ResultError)
            notifyEngineIll();
    };
    runCommand(cmd);
460 461
}

hjk's avatar
hjk committed
462
void LldbEngine::handleResponse(const QString &response)
463
{
464 465
    GdbMi all;
    all.fromStringMultiple(response);
466

467
    foreach (const GdbMi &item, all.children()) {
hjk's avatar
hjk committed
468
        const QString name = item.name();
469
        if (name == "result") {
hjk's avatar
hjk committed
470
            QString msg = item["status"].data();
hjk's avatar
hjk committed
471 472 473
            if (msg.size())
                msg[0] = msg.at(0).toUpper();
            showStatusMessage(msg);
474

475
            int token = item["token"].toInt();
hjk's avatar
hjk committed
476
            showMessage(QString("%1^").arg(token), LogOutput);
477 478 479 480 481 482 483 484 485 486 487 488 489 490
            if (m_commandForToken.contains(token)) {
                DebuggerCommand cmd = m_commandForToken.take(token);
                DebuggerResponse response;
                response.token = token;
                response.data = item;
                if (cmd.callback)
                    cmd.callback(response);
            }
        } else if (name == "state")
            handleStateNotification(item);
        else if (name == "location")
            handleLocationNotification(item);
        else if (name == "output")
            handleOutputNotification(item);
491 492
        else if (name == "pid")
            notifyInferiorPid(item.toLongLong());
493 494 495
    }
}

496 497
void LldbEngine::executeRunToLine(const ContextData &data)
{
498
    notifyInferiorRunRequested();
499
    DebuggerCommand cmd("executeRunToLocation");
hjk's avatar
hjk committed
500 501 502 503
    cmd.arg("file", data.fileName);
    cmd.arg("line", data.lineNumber);
    cmd.arg("address", data.address);
    runCommand(cmd);
504 505 506 507
}

void LldbEngine::executeRunToFunction(const QString &functionName)
{
508
    notifyInferiorRunRequested();
509 510 511
    DebuggerCommand cmd("executeRunToFunction");
    cmd.arg("function", functionName);
    runCommand(cmd);
512 513 514 515
}

void LldbEngine::executeJumpToLine(const ContextData &data)
{
516
    DebuggerCommand cmd("executeJumpToLocation");
517 518 519 520
    cmd.arg("file", data.fileName);
    cmd.arg("line", data.lineNumber);
    cmd.arg("address", data.address);
    runCommand(cmd);
521 522 523 524 525 526 527
}

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

528
    StackHandler *handler = stackHandler();
529 530
    if (frameIndex == handler->stackSize()) {
        fetchStack(handler->stackSize() * 10 + 3);
531 532
        return;
    }
533

534 535 536 537
    QTC_ASSERT(frameIndex < handler->stackSize(), return);
    handler->setCurrentIndex(frameIndex);
    gotoLocation(handler->currentFrame());

538
    DebuggerCommand cmd("activateFrame");
539 540 541
    cmd.arg("index", frameIndex);
    cmd.arg("thread", threadsHandler()->currentThread().raw());
    runCommand(cmd);
542 543 544

    updateLocals();
    reloadRegisters();
545 546 547 548
}

void LldbEngine::selectThread(ThreadId threadId)
{
549 550 551
    DebuggerCommand cmd("selectThread");
    cmd.arg("id", threadId.raw());
    cmd.callback = [this](const DebuggerResponse &) {
552
        fetchStack(action(MaximalStackDepth)->value().toInt());
553
    };
554
    runCommand(cmd);
555 556
}

557
bool LldbEngine::stateAcceptsBreakpointChanges() const
558
{
559 560 561 562 563 564 565 566 567 568
    switch (state()) {
    case InferiorSetupRequested:
    case InferiorRunRequested:
    case InferiorRunOk:
    case InferiorStopRequested:
    case InferiorStopOk:
        return true;
    default:
        return false;
    }
569 570
}

571
bool LldbEngine::acceptsBreakpoint(Breakpoint bp) const
572
{
573
    if (runParameters().startMode == AttachCore)
574
        return false;
575
    if (bp.parameters().isCppBreakpoint())
576
        return true;
577
    return isNativeMixedEnabled();
578
}
579

580 581 582
void LldbEngine::insertBreakpoint(Breakpoint bp)
{
    DebuggerCommand cmd("insertBreakpoint");
583 584 585 586
    cmd.callback = [this, bp](const DebuggerResponse &response) {
        QTC_CHECK(bp.state() == BreakpointInsertProceeding);
        updateBreakpointData(bp, response.data, true);
    };
587
    bp.addToCommand(&cmd);
588
    bp.notifyBreakpointInsertProceeding();
589
    runCommand(cmd);
590 591
}

592
void LldbEngine::changeBreakpoint(Breakpoint bp)
593
{
594 595
    const BreakpointResponse &response = bp.response();
    DebuggerCommand cmd("changeBreakpoint");
hjk's avatar
hjk committed
596
    cmd.arg("lldbid", response.id.toString());
597 598 599 600
    cmd.callback = [this, bp](const DebuggerResponse &response) {
        QTC_CHECK(!bp.isValid() || bp.state() == BreakpointChangeProceeding);
        updateBreakpointData(bp, response.data, false);
    };
601
    bp.addToCommand(&cmd);
602 603 604
    bp.notifyBreakpointChangeProceeding();
    runCommand(cmd);
}
605

606 607 608
void LldbEngine::removeBreakpoint(Breakpoint bp)
{
    const BreakpointResponse &response = bp.response();
609 610
    if (response.id.isValid()) {
        DebuggerCommand cmd("removeBreakpoint");
hjk's avatar
hjk committed
611
        cmd.arg("lldbid", response.id.toString());
612 613 614 615 616 617 618 619
        cmd.callback = [this, bp](const DebuggerResponse &) {
            QTC_CHECK(bp.state() == BreakpointRemoveProceeding);
            Breakpoint bp0 = bp;
            bp0.notifyBreakpointRemoveOk();
        };
        bp.notifyBreakpointRemoveProceeding();
        runCommand(cmd);
    }
620
}
621

622
void LldbEngine::updateBreakpointData(Breakpoint bp, const GdbMi &bkpt, bool added)
623 624
{
    BreakHandler *handler = breakHandler();
625
    BreakpointResponseId rid = BreakpointResponseId(bkpt["lldbid"].data());
626 627 628
    if (!bp.isValid())
        bp = handler->findBreakpointByResponseId(rid);
    BreakpointResponse response = bp.response();
629 630 631 632
    if (added)
        response.id = rid;
    QTC_CHECK(response.id == rid);
    response.address = 0;
633 634
    response.enabled = bkpt["enabled"].toInt();
    response.ignoreCount = bkpt["ignorecount"].toInt();
hjk's avatar
hjk committed
635
    response.condition = fromHex(bkpt["condition"].data());
636
    response.hitCount = bkpt["hitcount"].toInt();
hjk's avatar
hjk committed
637
    response.fileName = bkpt["file"].data();
638 639 640
    response.lineNumber = bkpt["line"].toInt();

    GdbMi locations = bkpt["locations"];
641
    const int numChild = int(locations.children().size());
642 643 644 645 646 647 648
    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();
hjk's avatar
hjk committed
649 650
            sub.functionName = location["func"].data();
            sub.fileName = location["file"].data();
651
            sub.lineNumber = location["line"].toInt();
652
            bp.insertSubBreakpoint(sub);
653
        }
654
        response.pending = false;
655 656 657
    } else if (numChild == 1) {
        const GdbMi location = locations.childAt(0);
        response.address = location["addr"].toAddress();
hjk's avatar
hjk committed
658
        response.functionName = location["func"].data();
659
        response.pending = false;
660
    } else {
661
        // This can happen for pending breakpoints.
hjk's avatar
hjk committed
662
        showMessage(QString("NO LOCATIONS (YET) FOR BP %1").arg(response.toString()));
663
    }
664
    bp.setResponse(response);
665
    if (added)
666
        bp.notifyBreakpointInsertOk();
667
    else
668
        bp.notifyBreakpointChangeOk();
669 670
}

671
void LldbEngine::handleOutputNotification(const GdbMi &output)
672
{
hjk's avatar
hjk committed
673 674
    QString channel = output["channel"].data();
    QString data = fromHex(output["data"].data());
675 676 677 678 679
    LogChannel ch = AppStuff;
    if (channel == "stdout")
        ch = AppOutput;
    else if (channel == "stderr")
        ch = AppError;
hjk's avatar
hjk committed
680
    showMessage(data, ch);
681 682
}

683 684 685 686 687 688 689 690 691 692 693
void LldbEngine::loadSymbols(const QString &moduleName)
{
    Q_UNUSED(moduleName)
}

void LldbEngine::loadAllSymbols()
{
}

void LldbEngine::reloadModules()
{
694 695 696 697 698 699 700
    DebuggerCommand cmd("fetchModules");
    cmd.callback = [this](const DebuggerResponse &response) {
        const GdbMi &modules = response.data["modules"];
        ModulesHandler *handler = modulesHandler();
        handler->beginUpdateAll();
        foreach (const GdbMi &item, modules.children()) {
            Module module;
hjk's avatar
hjk committed
701 702
            module.modulePath = item["file"].data();
            module.moduleName = item["name"].data();
703 704 705 706 707 708 709 710
            module.symbolsRead = Module::UnknownReadState;
            module.startAddress = item["loaded_addr"].toAddress();
            module.endAddress = 0; // FIXME: End address not easily available.
            handler->updateModule(module);
        }
        handler->endUpdateAll();
    };
    runCommand(cmd);
711 712 713 714
}

void LldbEngine::requestModuleSymbols(const QString &moduleName)
{
715
    DebuggerCommand cmd("fetchSymbols");
716
    cmd.arg("module", moduleName);
717 718
    cmd.callback = [this, moduleName](const DebuggerResponse &response) {
        const GdbMi &symbols = response.data["symbols"];
hjk's avatar
hjk committed
719
        QString moduleName = response.data["module"].data();
720 721 722
        Symbols syms;
        foreach (const GdbMi &item, symbols.children()) {
            Symbol symbol;
hjk's avatar
hjk committed
723 724 725 726 727
            symbol.address = item["address"].data();
            symbol.name = item["name"].data();
            symbol.state = item["state"].data();
            symbol.section = item["section"].data();
            symbol.demangled = item["demangled"].data();
728 729 730 731
            syms.append(symbol);
        }
        Internal::showModuleSymbols(moduleName, syms);
    };
732
    runCommand(cmd);
733 734
}

735

736 737 738 739 740 741
//////////////////////////////////////////////////////////////////////
//
// Tooltip specific stuff
//
//////////////////////////////////////////////////////////////////////

742
bool LldbEngine::canHandleToolTip(const DebuggerToolTipContext &context) const
743
{
744
   return state() == InferiorStopOk && context.isCppEditor;
745 746
}

747 748
void LldbEngine::updateAll()
{
749 750 751 752 753 754
    DebuggerCommand cmd("fetchThreads");
    cmd.callback = [this](const DebuggerResponse &response) {
        threadsHandler()->updateThreads(response.data);
        fetchStack(action(MaximalStackDepth)->value().toInt());
        reloadRegisters();
    };
755 756 757
    runCommand(cmd);
}

758
void LldbEngine::reloadFullStack()
759
{
760 761 762 763 764 765
    fetchStack(-1);
}

void LldbEngine::fetchStack(int limit)
{
    DebuggerCommand cmd("fetchStack");
766
    cmd.arg("nativemixed", isNativeMixedActive());
767
    cmd.arg("stacklimit", limit);
768
    cmd.arg("context", stackHandler()->currentFrame().context);
769 770
    cmd.callback = [this](const DebuggerResponse &response) {
        const GdbMi &stack = response.data["stack"];
771 772 773
        const bool isFull = !stack["hasmore"].toInt();
        stackHandler()->setFramesAndCurrentIndex(stack["frames"], isFull);
        activateFrame(stackHandler()->currentIndex());
774
    };
775 776 777
    runCommand(cmd);
}

778

779 780 781 782 783 784
//////////////////////////////////////////////////////////////////////
//
// Watch specific stuff
//
//////////////////////////////////////////////////////////////////////

785
void LldbEngine::assignValueInDebugger(WatchItem *,
786
    const QString &expression, const QVariant &value)
787
{
788
    DebuggerCommand cmd("assignValue");
hjk's avatar
hjk committed
789 790
    cmd.arg("exp", toHex(expression));
    cmd.arg("value", toHex(value.toString()));
791
    cmd.callback = [this](const DebuggerResponse &) { updateLocals(); };
792
    runCommand(cmd);
793 794
}

795
void LldbEngine::doUpdateLocals(const UpdateParameters &params)
796
{
797
    watchHandler()->notifyUpdateStarted(params);
798

799
    DebuggerCommand cmd("fetchVariables");
800
    watchHandler()->appendFormatRequests(&cmd);
hjk's avatar
hjk committed
801
    watchHandler()->appendWatchersAndTooltipRequests(&cmd);
802 803

    const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty();
hjk's avatar
hjk committed
804
    cmd.arg("passexceptions", alwaysVerbose);
hjk's avatar
hjk committed
805 806 807
    cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
    cmd.arg("autoderef", boolSetting(AutoDerefPointers));
    cmd.arg("dyntype", boolSetting(UseDynamicType));
808
    cmd.arg("partialvar", params.partialVariable);
809
    cmd.arg("qobjectnames", boolSetting(ShowQObjectNames));
hjk's avatar
hjk committed
810

811 812 813 814
    StackFrame frame = stackHandler()->currentFrame();
    cmd.arg("context", frame.context);
    cmd.arg("nativemixed", isNativeMixedActive());

815 816 817
    cmd.arg("stringcutoff", action(MaximalStringLength)->value().toString());
    cmd.arg("displaystringlimit", action(DisplayStringLimit)->value().toString());

818
    //cmd.arg("resultvarname", m_resultVarName);
819
    cmd.arg("partialvar", params.partialVariable);
820

821
    m_lastDebuggableCommand = cmd;
822
    m_lastDebuggableCommand.arg("passexceptions", "1");
823

824 825 826 827
    cmd.callback = [this](const DebuggerResponse &response) {
        updateLocalsView(response.data);
        watchHandler()->notifyUpdateFinished();
    };
828

829
    runCommand(cmd);
830 831 832 833
}

void LldbEngine::handleLldbError(QProcess::ProcessError error)
{
hjk's avatar
hjk committed
834
    showMessage(QString("LLDB PROCESS ERROR: %1").arg(error));
835 836 837 838 839 840 841 842 843 844
    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
845
        AsynchronousMessageBox::critical(tr("LLDB I/O Error"), errorMessage(error));
846 847 848 849 850 851 852 853
        break;
    }
}

QString LldbEngine::errorMessage(QProcess::ProcessError error) const
{
    switch (error) {
        case QProcess::FailedToStart:
Leena Miettinen's avatar
Leena Miettinen committed
854
            return tr("The LLDB process failed to start. Either the "
855
                "invoked program \"%1\" is missing, or you may have insufficient "
856
                "permissions to invoke the program.")
857
                .arg(runParameters().debugger.executable);
858
        case QProcess::Crashed:
Leena Miettinen's avatar
Leena Miettinen committed
859
            return tr("The LLDB process crashed some time after starting "
860 861 862 863 864 865 866
                "successfully.");
        case QProcess::Timedout:
            return tr("The last waitFor...() function timed out. "
                "The state of QProcess is unchanged, and you can try calling "
                "waitFor...() again.");
        case QProcess::WriteError:
            return tr("An error occurred when attempting to write "
Leena Miettinen's avatar
Leena Miettinen committed
867
                "to the LLDB process. For example, the process may not be running, "
868 869 870 871 872
                "or it may have closed its input channel.");
        case QProcess::ReadError:
            return tr("An error occurred when attempting to read from "
                "the Lldb process. For example, the process may not be running.");
        default:
hjk's avatar
hjk committed
873
            return tr("An unknown error in the LLDB process occurred.") + ' ';
874 875 876
    }
}

877
void LldbEngine::handleLldbFinished(int exitCode, QProcess::ExitStatus exitStatus)
878
{
879
    notifyDebuggerProcessFinished(exitCode, exitStatus, QLatin1String("LLDB"));
880 881 882 883
}

void LldbEngine::readLldbStandardError()
{
hjk's avatar
hjk committed
884
    QString err = QString::fromUtf8(m_lldbProc.readAllStandardError());
885
    qDebug() << "\nLLDB STDERR UNEXPECTED: " << err;
hjk's avatar
hjk committed
886
    showMessage("Lldb stderr: " + err, LogError);