lldbengine.cpp 42.6 KB
Newer Older
1
2
/****************************************************************************
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
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
** Contact: http://www.qt-project.org/legal
**
** 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
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "lldbengine.h"

32
33
34
#include <debugger/debuggeractions.h>
#include <debugger/debuggercore.h>
#include <debugger/debuggerdialogs.h>
Fawzi Mohamed's avatar
Fawzi Mohamed committed
35
#include <debugger/debuggerinternalconstants.h>
36
#include <debugger/debuggermainwindow.h>
37
38
39
40
41
#include <debugger/debuggerplugin.h>
#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 <utils/qtcassert.h>
54
#include <utils/savedaction.h>
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

#include <texteditor/itexteditor.h>
#include <coreplugin/idocument.h>
#include <coreplugin/icore.h>

#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QTimer>
#include <QVariant>

#include <QApplication>
#include <QMessageBox>
#include <QToolTip>

namespace Debugger {
namespace Internal {

74
75
76
77
78
static QByteArray tooltipIName(const QString &exp)
{
    return "tooltip." + exp.toLatin1().toHex();
}

79
80
81
82
83
84
85
///////////////////////////////////////////////////////////////////////
//
// LldbEngine
//
///////////////////////////////////////////////////////////////////////

LldbEngine::LldbEngine(const DebuggerStartParameters &startParameters)
86
    : DebuggerEngine(startParameters), m_continueAtNextSpontaneousStop(false)
87
{
88
    m_lastAgentId = 0;
hjk's avatar
hjk committed
89
    m_lastToken = 0;
90
    setObjectName(QLatin1String("LldbEngine"));
91
92
93
94
95
96
97
98
99
100
101

    connect(debuggerCore()->action(AutoDerefPointers), SIGNAL(valueChanged(QVariant)),
            SLOT(updateLocals()));
    connect(debuggerCore()->action(CreateFullBacktrace), SIGNAL(triggered()),
            SLOT(updateAll()));
    connect(debuggerCore()->action(UseDebuggingHelpers), SIGNAL(valueChanged(QVariant)),
            SLOT(updateLocals()));
    connect(debuggerCore()->action(UseDynamicType), SIGNAL(valueChanged(QVariant)),
            SLOT(updateLocals()));
    connect(debuggerCore()->action(IntelFlavor), SIGNAL(valueChanged(QVariant)),
            SLOT(updateAll()));
102
103
104
105
106
}

LldbEngine::~LldbEngine()
{}

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

hjk's avatar
hjk committed
112
void LldbEngine::runCommand(const Command &command)
113
114
{
    QTC_ASSERT(m_lldbProc.state() == QProcess::Running, notifyEngineIll());
hjk's avatar
hjk committed
115
116
    ++m_lastToken;
    QByteArray token = QByteArray::number(m_lastToken);
117
118
    QByteArray cmd = "{\"cmd\":\"" + command.function + "\","
        + command.args + "\"token\":" + token + "}\n";
hjk's avatar
hjk committed
119
    showMessage(_(token + cmd), LogInput);
120
    m_lldbProc.write(cmd);
121
122
}

123
124
125
126
127
void LldbEngine::debugLastCommand()
{
    runCommand(m_lastDebuggableCommand);
}

128
129
130
void LldbEngine::shutdownInferior()
{
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
131
    runCommand(Command("shutdownInferior"));
132
133
134
135
136
137
138
139
}

void LldbEngine::shutdownEngine()
{
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
    m_lldbProc.kill();
}

140
141
142
143
144
145
146
147
148
149
150
151
152
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();
    }
}

153
154
155
void LldbEngine::setupEngine()
{
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
Orgad Shaneh's avatar
Orgad Shaneh committed
156
    if (startParameters().remoteSetupNeeded)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
157
        notifyEngineRequestRemoteSetup();
Orgad Shaneh's avatar
Orgad Shaneh committed
158
    else
Fawzi Mohamed's avatar
Fawzi Mohamed committed
159
160
        startLldb();
}
161

Fawzi Mohamed's avatar
Fawzi Mohamed committed
162
163
void LldbEngine::startLldb()
{
164
    m_lldbCmd = startParameters().debuggerCommand;
165
166
167
168
169
170
171
172
173
174
    connect(&m_lldbProc, SIGNAL(error(QProcess::ProcessError)),
        SLOT(handleLldbError(QProcess::ProcessError)));
    connect(&m_lldbProc, SIGNAL(finished(int,QProcess::ExitStatus)),
        SLOT(handleLldbFinished(int,QProcess::ExitStatus)));
    connect(&m_lldbProc, SIGNAL(readyReadStandardOutput()),
        SLOT(readLldbStandardOutput()));
    connect(&m_lldbProc, SIGNAL(readyReadStandardError()),
        SLOT(readLldbStandardError()));

    connect(this, SIGNAL(outputReady(QByteArray)),
175
        SLOT(handleResponse(QByteArray)), Qt::QueuedConnection);
176

177
178
179
180
    QStringList args;
    args.append(_("-i"));
    args.append(Core::ICore::resourcePath() + _("/debugger/lldbbridge.py"));
    args.append(m_lldbCmd);
Andre Hartmann's avatar
Andre Hartmann committed
181
    showMessage(_("STARTING LLDB ") + args.join(QLatin1String(" ")));
182
    m_lldbProc.setEnvironment(startParameters().environment.toStringList());
Eike Ziller's avatar
Eike Ziller committed
183
184
    if (!startParameters().workingDirectory.isEmpty())
        m_lldbProc.setWorkingDirectory(startParameters().workingDirectory);
185

186
    m_lldbProc.start(_("python"), args);
187
188

    if (!m_lldbProc.waitForStarted()) {
189
        const QString msg = tr("Unable to start LLDB \"%1\": %2")
190
            .arg(m_lldbCmd, m_lldbProc.errorString());
191
192
        notifyEngineSetupFailed();
        showMessage(_("ADAPTER START FAILED"));
193
        if (!msg.isEmpty())
194
            Core::ICore::showWarningWithOptions(tr("Adapter start failed."), msg);
195
196
197
198
199
    }
}

void LldbEngine::setupInferior()
{
200
201
202
    const DebuggerStartParameters &sp = startParameters();
    Command cmd("setupInferior");
    cmd.arg("executable", QFileInfo(sp.executable).absoluteFilePath());
Fawzi Mohamed's avatar
Fawzi Mohamed committed
203
    cmd.arg("startMode", sp.startMode); // directly relying on this is brittle wrt. insertions, so check it here
204
    cmd.arg("processArgs", sp.processArgs);
205

206
207
208
    // 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
209
210
                                || sp.startMode == AttachExternal));
    cmd.arg("attachPid", sp.attachPID);
Fawzi Mohamed's avatar
Fawzi Mohamed committed
211
    cmd.arg("sysRoot", sp.deviceSymbolsRoot.isEmpty() ? sp.sysRoot : sp.deviceSymbolsRoot);
Fawzi Mohamed's avatar
Fawzi Mohamed committed
212
213
    cmd.arg("remoteChannel", ((sp.startMode == AttachToRemoteProcess
                               || sp.startMode == AttachToRemoteServer)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
214
                              ? sp.remoteChannel : QString()));
215
    cmd.arg("platform", sp.platform);
216
217
218
219
    QTC_CHECK(!sp.continueAfterAttach || (sp.startMode == AttachToRemoteProcess
                                          || sp.startMode == AttachExternal
                                          || sp.startMode == AttachToRemoteServer));
    m_continueAtNextSpontaneousStop = false;
220
    runCommand(cmd);
221
    updateLocals(); // update display options
222
223
224
225
226
}

void LldbEngine::runEngine()
{
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
227

hjk's avatar
hjk committed
228
229
    Command cmd("handleBreakpoints");
    if (attemptBreakpointSynchronizationHelper(&cmd)) {
230
        runEngine2();
hjk's avatar
hjk committed
231
232
233
234
    } else {
        cmd.arg("continuation", "runEngine2");
        runCommand(cmd);
    }
235
236
237
238
}

void LldbEngine::runEngine2()
{
239
    showStatusMessage(tr("Running requested..."), 5000);
240
    runCommand("runEngine");
241
242
243
244
245
}

void LldbEngine::interruptInferior()
{
    showStatusMessage(tr("Interrupt requested..."), 5000);
246
    runCommand("interruptInferior");
247
248
}

249
250
251
252
void LldbEngine::executeStep()
{
    resetLocation();
    notifyInferiorRunRequested();
253
    runCommand("executeStep");
254
255
}

256
257
258
259
void LldbEngine::executeStepI()
{
    resetLocation();
    notifyInferiorRunRequested();
260
    runCommand("executeStepI");
261
262
263
264
265
266
}

void LldbEngine::executeStepOut()
{
    resetLocation();
    notifyInferiorRunRequested();
267
    runCommand("executeStepOut");
268
269
270
271
272
273
}

void LldbEngine::executeNext()
{
    resetLocation();
    notifyInferiorRunRequested();
274
    runCommand("executeNext");
275
276
277
278
279
280
}

void LldbEngine::executeNextI()
{
    resetLocation();
    notifyInferiorRunRequested();
281
    runCommand("executeNextI");
282
283
284
285
286
287
}

void LldbEngine::continueInferior()
{
    resetLocation();
    notifyInferiorRunRequested();
288
    runCommand("continueInferior");
289
290
}

291
void LldbEngine::handleResponse(const QByteArray &response)
292
{
293
294
    GdbMi all;
    all.fromStringMultiple(response);
295

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
    foreach (const GdbMi &item, all.children()) {
        const QByteArray name = item.name();
        if (name == "data")
            refreshLocals(item);
        else if (name == "stack")
            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);
314
315
        else if (name == "symbols")
            refreshSymbols(item);
316
317
        else if (name == "bkpts")
            refreshBreakpoints(item);
318
319
        else if (name == "output")
            refreshOutput(item);
320
321
        else if (name == "disassembly")
            refreshDisassembly(item);
322
323
        else if (name == "memory")
            refreshMemory(item);
324
325
326
327
328
329
330
331
332
        else if (name == "continuation")
            runContinuation(item);
    }
}

void LldbEngine::runContinuation(const GdbMi &data)
{
    const QByteArray target = data.data();
    QMetaObject::invokeMethod(this, target, Qt::QueuedConnection);
333
334
}

335
336
void LldbEngine::executeRunToLine(const ContextData &data)
{
337
338
    resetLocation();
    notifyInferiorRunRequested();
hjk's avatar
hjk committed
339
340
    runCommand(Command("executeRunToLine")
        .arg("file", data.fileName).arg("line", data.address));
341
342
343
344
}

void LldbEngine::executeRunToFunction(const QString &functionName)
{
345
346
    resetLocation();
    notifyInferiorRunRequested();
hjk's avatar
hjk committed
347
    runCommand(Command("executeRunToFunction").arg("function", functionName));
348
349
350
351
}

void LldbEngine::executeJumpToLine(const ContextData &data)
{
352
353
    resetLocation();
    notifyInferiorRunRequested();
hjk's avatar
hjk committed
354
355
    runCommand(Command("executeJumpToLine")
        .arg("file", data.fileName).arg("line", data.address));
356
357
358
359
360
361
362
363
}

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

hjk's avatar
hjk committed
364
    runCommand(Command("activateFrame").arg("index", frameIndex));
365
366
367
368
}

void LldbEngine::selectThread(ThreadId threadId)
{
hjk's avatar
hjk committed
369
    runCommand(Command("selectThread").arg("id", threadId.raw()));
370
371
372
373
374
375
376
377
}

bool LldbEngine::acceptsBreakpoint(BreakpointModelId id) const
{
    return breakHandler()->breakpointData(id).isCppBreakpoint()
        && startParameters().startMode != AttachCore;
}

hjk's avatar
hjk committed
378
bool LldbEngine::attemptBreakpointSynchronizationHelper(Command *cmd)
379
380
381
{
    BreakHandler *handler = breakHandler();

382
383
384
385
386
387
388
389
390
391
392
393
394
    foreach (BreakpointModelId id, handler->unclaimedBreakpointIds()) {
        // Take ownership of the breakpoint. Requests insertion.
        if (acceptsBreakpoint(id)) {
            showMessage(_("TAKING OWNERSHIP OF BREAKPOINT %1 IN STATE %2")
                .arg(id.toString()).arg(handler->state(id)));
            handler->setEngine(id, this);
        } else {
            showMessage(_("BREAKPOINT %1 IN STATE %2 IS NOT ACCEPTABLE")
                .arg(id.toString()).arg(handler->state(id)));
        }
    }

    bool done = true;
hjk's avatar
hjk committed
395
    cmd->beginList("bkpts");
396
397
    foreach (BreakpointModelId id, handler->engineBreakpointIds(this)) {
        const BreakpointResponse &response = handler->response(id);
398
399
        const BreakpointState bpState = handler->state(id);
        switch (bpState) {
400
401
402
403
404
405
        case BreakpointNew:
            // Should not happen once claimed.
            QTC_CHECK(false);
            break;
        case BreakpointInsertRequested:
            done = false;
hjk's avatar
hjk committed
406
407
408
409
410
            cmd->beginGroup()
                    .arg("operation", "add")
                    .arg("modelid", id.toByteArray())
                    .arg("type", handler->type(id))
                    .arg("ignorecount", handler->ignoreCount(id))
411
                    .arg("condition", handler->condition(id).toHex())
hjk's avatar
hjk committed
412
413
414
415
416
                    .arg("function", handler->functionName(id).toUtf8())
                    .arg("oneshot", handler->isOneShot(id))
                    .arg("enabled", handler->isEnabled(id))
                    .arg("file", handler->fileName(id).toUtf8())
                    .arg("line", handler->lineNumber(id))
417
418
                    .arg("address", handler->address(id))
                    .arg("expression", handler->expression(id))
hjk's avatar
hjk committed
419
                    .endGroup();
420
421
422
423
            handler->notifyBreakpointInsertProceeding(id);
            break;
        case BreakpointChangeRequested:
            done = false;
hjk's avatar
hjk committed
424
425
426
427
428
429
            cmd->beginGroup()
                    .arg("operation", "change")
                    .arg("modelid", id.toByteArray())
                    .arg("lldbid", response.id.toByteArray())
                    .arg("type", handler->type(id))
                    .arg("ignorecount", handler->ignoreCount(id))
430
                    .arg("condition", handler->condition(id).toHex())
hjk's avatar
hjk committed
431
432
433
434
435
                    .arg("function", handler->functionName(id).toUtf8())
                    .arg("oneshot", handler->isOneShot(id))
                    .arg("enabled", handler->isEnabled(id))
                    .arg("file", handler->fileName(id).toUtf8())
                    .arg("line", handler->lineNumber(id))
436
437
                    .arg("address", handler->address(id))
                    .arg("expression", handler->expression(id))
hjk's avatar
hjk committed
438
                    .endGroup();
439
440
441
442
            handler->notifyBreakpointChangeProceeding(id);
            break;
        case BreakpointRemoveRequested:
            done = false;
hjk's avatar
hjk committed
443
444
445
446
447
            cmd->beginGroup()
                    .arg("operation", "remove")
                    .arg("modelid", id.toByteArray())
                    .arg("lldbid", response.id.toByteArray())
                    .endGroup();
448
449
450
451
452
453
454
            handler->notifyBreakpointRemoveProceeding(id);
            break;
        case BreakpointChangeProceeding:
        case BreakpointInsertProceeding:
        case BreakpointRemoveProceeding:
        case BreakpointInserted:
        case BreakpointDead:
455
            QTC_ASSERT(false, qDebug() << "UNEXPECTED STATE" << bpState << "FOR BP " << id);
456
457
            break;
        default:
458
            QTC_ASSERT(false, qDebug() << "UNKNOWN STATE" << bpState << "FOR BP" << id);
459
460
        }
    }
hjk's avatar
hjk committed
461
    cmd->endList();
462
463
464
465
466
467
468
469
470
471
    return done;
}

void LldbEngine::attemptBreakpointSynchronization()
{
    showMessage(_("ATTEMPT BREAKPOINT SYNCHRONIZATION"));
    if (!stateAcceptsBreakpointChanges()) {
        showMessage(_("BREAKPOINT SYNCHRONIZATION NOT POSSIBLE IN CURRENT STATE"));
        return;
    }
472

hjk's avatar
hjk committed
473
474
    Command cmd("handleBreakpoints");
    if (!attemptBreakpointSynchronizationHelper(&cmd)) {
475
        showMessage(_("BREAKPOINTS ARE NOT FULLY SYNCHRONIZED"));
hjk's avatar
hjk committed
476
        runCommand(cmd);
477
478
479
480
    } else {
        showMessage(_("BREAKPOINTS ARE SYNCHRONIZED"));
    }
}
481

482
void LldbEngine::updateBreakpointData(const GdbMi &bkpt, bool added)
483
484
{
    BreakHandler *handler = breakHandler();
485
    BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
486
    BreakpointResponse response = handler->response(id);
487
    BreakpointResponseId rid = BreakpointResponseId(bkpt["lldbid"].data());
488
489
490
491
    if (added)
        response.id = rid;
    QTC_CHECK(response.id == rid);
    response.address = 0;
492
493
    response.enabled = bkpt["enabled"].toInt();
    response.ignoreCount = bkpt["ignorecount"].toInt();
494
    response.condition = QByteArray::fromHex(bkpt["condition"].data());
495
    response.hitCount = bkpt["hitcount"].toInt();
496
497
498

    if (added) {
        // Added.
499
        GdbMi locations = bkpt["locations"];
500
501
502
        const int numChild = locations.children().size();
        if (numChild > 1) {
            foreach (const GdbMi &location, locations.children()) {
503
                const int locid = location["locid"].toInt();
504
                BreakpointResponse sub;
505
                sub.id = BreakpointResponseId(rid.majorPart(), locid);
506
                sub.type = response.type;
507
                sub.address = location["addr"].toAddress();
508
                sub.functionName = location["func"].toUtf8();
509
510
511
512
                handler->insertSubBreakpoint(id, sub);
            }
        } else if (numChild == 1) {
            const GdbMi location = locations.childAt(0);
513
            response.address = location["addr"].toAddress();
514
            response.functionName = location["func"].toUtf8();
515
516
517
518
519
520
521
522
523
524
525
526
        } else {
            QTC_CHECK(false);
        }
        handler->setResponse(id, response);
        handler->notifyBreakpointInsertOk(id);
    } else {
        // Changed.
        handler->setResponse(id, response);
        handler->notifyBreakpointChangeOk(id);
    }
}

527
void LldbEngine::refreshDisassembly(const GdbMi &data)
528
529
530
{
    DisassemblerLines result;

531
    int cookie = data["cookie"].toInt();
532
533
534
535
    QPointer<DisassemblerAgent> agent = m_disassemblerAgents.key(cookie);
    if (!agent.isNull()) {
        foreach (const GdbMi &line, data["lines"].children()) {
            DisassemblerLine dl;
536
            dl.address = line["address"].toAddress();
537
538
            dl.data = line["inst"].toUtf8();
            dl.function = line["func-name"].toUtf8();
539
            dl.offset = line["offset"].toInt();
540
541
542
            QByteArray comment = line["comment"].data();
            if (!comment.isEmpty())
                dl.data += QString::fromUtf8(" # " + comment);
543
544
545
            result.appendLine(dl);
        }
        agent->setContents(result);
546
    }
547
}
548

549
550
void LldbEngine::refreshMemory(const GdbMi &data)
{
551
    int cookie = data["cookie"].toInt();
552
    qulonglong addr = data["address"].toAddress();
553
554
555
556
557
558
559
    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);
    }
560
561
}

562
563
564
565
566
567
568
569
570
571
572
573
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);
}

574
void LldbEngine::refreshBreakpoints(const GdbMi &bkpts)
575
{
576
    BreakHandler *handler = breakHandler();
hjk's avatar
hjk committed
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
    foreach (const GdbMi &bkpt, bkpts.children()) {
        QByteArray op = bkpt["operation"].data();
        if (op == "added") {
            BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
            QTC_CHECK(handler->state(id) == BreakpointInsertProceeding);
            updateBreakpointData(bkpt, true);
        } else if (op == "changed") {
            BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
            QTC_CHECK(handler->state(id) == BreakpointChangeProceeding);
            updateBreakpointData(bkpt, false);
        } else if (op == "removed") {
            BreakpointModelId id = BreakpointModelId(bkpt["modelid"].data());
            QTC_CHECK(handler->state(id) == BreakpointRemoveProceeding);
            handler->notifyBreakpointRemoveOk(id);
        }
592
    }
593
594
595
596
597
598
599
600
601
602
603
604
605
}

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

void LldbEngine::loadAllSymbols()
{
}

void LldbEngine::reloadModules()
{
606
    runCommand("listModules");
607
608
}

609
void LldbEngine::refreshModules(const GdbMi &modules)
610
{
611
612
    Modules mods;
    foreach (const GdbMi &item, modules.children()) {
613
        Module module;
614
615
        module.modulePath = item["file"].toUtf8();
        module.moduleName = item["name"].toUtf8();
616
        module.symbolsRead = Module::UnknownReadState;
617
        module.startAddress = item["loaded_addr"].toAddress();
618
        module.endAddress = 0; // FIXME: End address not easily available.
619
        mods.append(module);
620
    }
621
    modulesHandler()->setModules(mods);
622
623
624
625
}

void LldbEngine::requestModuleSymbols(const QString &moduleName)
{
626
    runCommand(Command("listSymbols").arg("module", moduleName));
627
628
}

629
void LldbEngine::refreshSymbols(const GdbMi &symbols)
630
{
631
    QString moduleName = symbols["module"].toUtf8();
632
633
634
    Symbols syms;
    foreach (const GdbMi &item, symbols["symbols"].children()) {
        Symbol symbol;
635
636
637
638
639
        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();
640
641
642
        syms.append(symbol);
    }
   debuggerCore()->showModuleSymbols(moduleName, syms);
643
644
}

645

646
647
648
649
650
651
652
653
654
655
//////////////////////////////////////////////////////////////////////
//
// Tooltip specific stuff
//
//////////////////////////////////////////////////////////////////////

static WatchData m_toolTip;
static QPoint m_toolTipPos;
static QHash<QString, WatchData> m_toolTipCache;

656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
void LldbEngine::showToolTip()
{
    if (m_toolTipContext.isNull())
        return;
    const QString expression = m_toolTipContext->expression;
    if (DebuggerToolTipManager::debug())
        qDebug() << "LldbEngine::showToolTip " << expression << m_toolTipContext->iname << (*m_toolTipContext);

    if (m_toolTipContext->iname.startsWith("tooltip")
        && (!debuggerCore()->boolSetting(UseToolTipsInMainEditor)
            || !watchHandler()->isValidToolTip(m_toolTipContext->iname))) {
        watchHandler()->removeData(m_toolTipContext->iname);
        return;
    }

    DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
    tw->setContext(*m_toolTipContext);
    tw->acquireEngine(this);
    DebuggerToolTipManager::showToolTip(m_toolTipContext->mousePosition, tw);
    // Prevent tooltip from re-occurring (classic GDB, QTCREATORBUG-4711).
    m_toolTipContext.reset();
}

void LldbEngine::resetLocation()
{
    m_toolTipContext.reset();
    DebuggerEngine::resetLocation();
}

685
bool LldbEngine::setToolTipExpression(const QPoint &mousePos,
686
    TextEditor::ITextEditor *editor, const DebuggerToolTipContext &contextIn)
687
{
688
689
690
    if (state() != InferiorStopOk || !isCppEditor(editor)) {
        //qDebug() << "SUPPRESSING DEBUGGER TOOLTIP, INFERIOR NOT STOPPED "
        // " OR NOT A CPPEDITOR";
691
692
693
        return false;
    }

694
695
696
697
    DebuggerToolTipContext context = contextIn;
    int line, column;
    QString exp = fixCppExpression(cppExpressionAt(editor, context.position, &line, &column, &context.function));
    if (exp.isEmpty())
698
        return false;
699
700
701
702
703
704
705
    // Prefer a filter on an existing local variable if it can be found.
    QByteArray iname;
    if (const WatchData *localVariable = watchHandler()->findCppLocalVariable(exp)) {
        exp = QLatin1String(localVariable->exp);
        iname = localVariable->iname;
    } else {
        iname = tooltipIName(exp);
706
707
    }

708
709
    if (DebuggerToolTipManager::debug())
        qDebug() << "GdbEngine::setToolTipExpression1 " << exp << iname << context;
710

711
712
713
    // Same expression: Display synchronously.
    if (!m_toolTipContext.isNull() && m_toolTipContext->expression == exp) {
        showToolTip();
714
715
716
        return true;
    }

717
718
719
720
721
722
723
    m_toolTipContext.reset(new DebuggerToolTipContext(context));
    m_toolTipContext->mousePosition = mousePos;
    m_toolTipContext->expression = exp;
    m_toolTipContext->iname = iname;
    // Local variable: Display synchronously.
    if (iname.startsWith("local")) {
        showToolTip();
724
725
726
        return true;
    }

727
728
    if (DebuggerToolTipManager::debug())
        qDebug() << "GdbEngine::setToolTipExpression2 " << exp << (*m_toolTipContext);
729

730
731
732
733
734
735
736
    UpdateParameters params;
    params.tryPartial = true;
    params.tooltipOnly = true;
    params.varList = iname;
    doUpdateLocals(params);

    return true;
737
738
}

739
740
741
742
void LldbEngine::updateAll()
{
    updateLocals();
}
743
744
745
746
747
748
749

//////////////////////////////////////////////////////////////////////
//
// Watch specific stuff
//
//////////////////////////////////////////////////////////////////////

750
751
void LldbEngine::assignValueInDebugger(const Internal::WatchData *data,
    const QString &expression, const QVariant &value)
752
{
753
754
755
756
757
    Q_UNUSED(data);
    Command cmd("assignValue");
    cmd.arg("exp", expression.toLatin1().toHex());
    cmd.arg("value", value.toString().toLatin1().toHex());
    runCommand(cmd);
758
759
760
761
762
763
}

void LldbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &flags)
{
    Q_UNUSED(data);
    Q_UNUSED(flags);
764
765
766
767
    updateLocals();
}

void LldbEngine::updateLocals()
768
769
770
771
772
773
{
    UpdateParameters params;
    doUpdateLocals(params);
}

void LldbEngine::doUpdateLocals(UpdateParameters params)
774
{
775
    WatchHandler *handler = watchHandler();
776
777
778
779
780
781
782

    Command cmd("updateData");
    cmd.arg("expanded", handler->expansionRequests());
    cmd.arg("typeformats", handler->typeFormatRequests());
    cmd.arg("formats", handler->individualFormatRequests());

    const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty();
hjk's avatar
hjk committed
783
    cmd.arg("passexceptions", alwaysVerbose);
784
785
786
    cmd.arg("fancy", debuggerCore()->boolSetting(UseDebuggingHelpers));
    cmd.arg("autoderef", debuggerCore()->boolSetting(AutoDerefPointers));
    cmd.arg("dyntype", debuggerCore()->boolSetting(UseDynamicType));
787
788
    cmd.arg("partial", params.tryPartial);
    cmd.arg("tooltiponly", params.tooltipOnly);
hjk's avatar
hjk committed
789
790

    cmd.beginList("watchers");
791
    // Watchers
hjk's avatar
hjk committed
792
793
794
795
796
797
    QHashIterator<QByteArray, int> it(WatchHandler::watcherNames());
    while (it.hasNext()) {
        it.next();
        cmd.beginGroup()
            .arg("iname", "watch." + QByteArray::number(it.value()))
            .arg("exp", it.key().toHex())
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
        .endGroup();
    }
    // Tooltip
    const StackFrame frame = stackHandler()->currentFrame();
    if (!frame.file.isEmpty()) {
        // Re-create tooltip items that are not filters on existing local variables in
        // the tooltip model.
        DebuggerToolTipContexts toolTips =
            DebuggerToolTipManager::treeWidgetExpressions(frame.file, objectName(), frame.function);

        const QString currentExpression =
             m_toolTipContext.isNull() ? QString() : m_toolTipContext->expression;
        if (!currentExpression.isEmpty()) {
            int currentIndex = -1;
            for (int i = 0; i < toolTips.size(); ++i) {
                if (toolTips.at(i).expression == currentExpression) {
                    currentIndex = i;
                    break;
                }
            }
            if (currentIndex < 0) {
                DebuggerToolTipContext context;
                context.expression = currentExpression;
                context.iname = tooltipIName(currentExpression);
                toolTips.push_back(context);
            }
        }
        foreach (const DebuggerToolTipContext &p, toolTips) {
            if (p.iname.startsWith("tooltip"))
                cmd.beginGroup()
                    .arg("iname", p.iname)
                    .arg("exp", p.expression.toLatin1().toHex())
                .endGroup();
        }
hjk's avatar
hjk committed
832
833
834
    }
    cmd.endList();

835
836
    //cmd.arg("resultvarname", m_resultVarName);

837
838
839
    m_lastDebuggableCommand = cmd;
    m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1");

840
    runCommand(cmd);
841
842

    reloadRegisters();
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
}

void LldbEngine::handleLldbError(QProcess::ProcessError error)
{
    qDebug() << "HANDLE LLDB ERROR";
    showMessage(_("HANDLE LLDB ERROR"));
    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();
Leena Miettinen's avatar
Leena Miettinen committed
859
        showMessageBox(QMessageBox::Critical, tr("LLDB I/O Error"),
860
861
862
863
864
865
866
867
868
                       errorMessage(error));
        break;
    }
}

QString LldbEngine::errorMessage(QProcess::ProcessError error) const
{
    switch (error) {
        case QProcess::FailedToStart:
Leena Miettinen's avatar
Leena Miettinen committed
869
            return tr("The LLDB process failed to start. Either the "
870
                "invoked program \"%1\" is missing, or you may have insufficient "
871
                "permissions to invoke the program.")
872
                .arg(m_lldbCmd);
873
        case QProcess::Crashed:
Leena Miettinen's avatar
Leena Miettinen committed
874
            return tr("The LLDB process crashed some time after starting "
875
876
877
878
879
880
881
                "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
882
                "to the LLDB process. For example, the process may not be running, "
883
884
885
886
887
                "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:
Friedemann Kleint's avatar
Friedemann Kleint committed
888
            return tr("An unknown error in the LLDB process occurred.") + QLatin1Char(' ');
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
    }
}

void LldbEngine::handleLldbFinished(int code, QProcess::ExitStatus type)
{
    qDebug() << "LLDB FINISHED";
    showMessage(_("LLDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
    notifyEngineSpontaneousShutdown();
}

void LldbEngine::readLldbStandardError()
{
    QByteArray err = m_lldbProc.readAllStandardError();
    qDebug() << "\nLLDB STDERR" << err;
    //qWarning() << "Unexpected lldb stderr:" << err;
904
    showMessage(_(err), LogError);
905
906
907
908
909
}

void LldbEngine::readLldbStandardOutput()
{
    QByteArray out = m_lldbProc.readAllStandardOutput();
910
    showMessage(_("Lldb stdout: " + out));
911
    m_inbuffer.append(out);
912
    while (true) {
913
        int pos = m_inbuffer.indexOf("@\n");
914
915
916
        if (pos == -1)
            break;
        QByteArray response = m_inbuffer.left(pos).trimmed();
917
        m_inbuffer = m_inbuffer.mid(pos + 2);
918
919
920
921
        emit outputReady(response);
    }
}

922
923
924
925
void LldbEngine::refreshLocals(const GdbMi &vars)
{
    //const bool partial = response.cookie.toBool();
    WatchHandler *handler = watchHandler();
926
    handler->resetValueCache();
927
928
929
930
931
    QList<WatchData> list;

    //if (!partial) {
        list.append(*handler->findData("local"));
        list.append(*handler->findData("watch"));
932
        list.append(*handler->findData("tooltip"));
933
934
935
936
937
        list.append(*handler->findData("return"));
    //}

    foreach (const GdbMi &child, vars.children()) {
        WatchData dummy;
938
939
        dummy.iname = child["iname"].data();
        GdbMi wname = child["wname"];
940
        if (wname.isValid()) {
941
942
943
            // Happens (only) for watched expressions.
            dummy.exp = QByteArray::fromHex(wname.data());
            dummy.name = QString::fromUtf8(dummy.exp);
944
        } else {
945
            dummy.name = child["name"].toUtf8();
946
        }
947
948
949
        parseWatchData(handler->expandedINames(), dummy, child, &list);
    }
    handler->insertData(list);
950
951

    showToolTip();
952
953
954
955
956
957
958
959
 }

void LldbEngine::refreshStack(const GdbMi &stack)
{
    //if (!partial)
    //    emit stackFrameCompleted();
    StackHandler *handler = stackHandler();
    StackFrames frames;
960
    foreach (const GdbMi &item, stack["frames"].children()) {
961
        StackFrame frame;
962
        frame.level = item["level"].toInt();
963
964
965
        frame.file = item["file"].toUtf8();
        frame.function = item["func"].toUtf8();
        frame.from = item["func"].toUtf8();
966
        frame.line = item["line"].toInt();
967
        frame.address = item["addr"].toAddress();
968
969
970
        frame.usable = QFileInfo(frame.file).isReadable();
        frames.append(frame);
    }
971
    bool canExpand = stack["hasmore"].toInt();
972
973
    debuggerCore()->action(ExpandStack)->setEnabled(canExpand);
    handler->setFrames(frames);
974
975
976

    int index = stack["current-frame"].toInt();
    handler->setCurrentIndex(index);
977
978
979
980
981
982
983
984
}

void LldbEngine::refreshRegisters(const GdbMi &registers)
{
    RegisterHandler *handler = registerHandler();
    Registers regs;
    foreach (const GdbMi &item, registers.children()) {
        Register reg;
985
986
        reg.name = item["name"].data();
        reg.value = item["value"].data();
987
        //reg.type = item["type"].data();
988
989
990
991
992
        regs.append(reg);
    }
    //handler->setRegisters(registers);
    handler->setAndMarkRegisters(regs);
}
993
994
995
996
997
998
999
1000
1001

void LldbEngine::refreshThreads(const GdbMi &threads)
{
    ThreadsHandler *handler = threadsHandler();
    handler->updateThreads(threads);
    if (!handler->currentThread().isValid()) {
        ThreadId other = handler->threadAt(0);
        if (other.isValid())
            selectThread(other);
1002
    }
1003
    updateViews(); // Adjust Threads combobox.
hjk's avatar
hjk committed
1004
1005
}

1006
void LldbEngine::refreshTypeInfo(const GdbMi &typeInfo)
hjk's avatar
hjk committed
1007
{
1008
1009
    if (typeInfo.type() == GdbMi::List) {
//        foreach (const GdbMi &s, typeInfo.children()) {
1010
1011
//            const GdbMi name = s["name"];
//            const GdbMi size = s["size"];
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
//            if (name.isValid() && size.isValid())
//                m_typeInfoCache.insert(QByteArray::fromBase64(name.data()),
//                                       TypeInfo(size.data().toUInt()));
//        }
    }
//    for (int i = 0; i != list.size(); ++i) {
//        const TypeInfo ti = m_typeInfoCache.value(list.at(i).type);
//        if (ti.size)
//            list[i].size = ti.size;
//    }
}
hjk's avatar
hjk committed
1023

1024
1025
void LldbEngine::refreshState(const GdbMi &reportedState)
{
1026
1027
1028
1029
1030
    QByteArray newState = reportedState.data();
    if (newState == "running")
        notifyInferiorRunOk();
    else if (newState == "inferiorrunfailed")
        notifyInferiorRunFailed();
1031
    else if (newState == "stopped") {
1032
        notifyInferiorSpontaneousStop();
1033
1034
1035
1036
1037
        if (m_continueAtNextSpontaneousStop) {
            m_continueAtNextSpontaneousStop = false;
            continueInferior();
        }
    } else if (newState == "inferiorstopok")
1038
1039
1040
1041
1042
1043
1044
        notifyInferiorStopOk();
    else if (newState == "inferiorstopfailed")
        notifyInferiorStopFailed();
    else if (newState == "enginesetupok")
        notifyEngineSetupOk();
    else if (newState == "enginesetupfailed")
        notifyEngineSetupFailed();
1045
1046
    else if (newState == "enginerunfailed")
        notifyEngineRunFailed();
1047
1048
    else if (newState == "inferiorsetupok")
        notifyInferiorSetupOk();
1049
1050
1051
    else if (newState == "enginerunandinferiorrunok") {
        if (startParameters().continueAfterAttach)
            m_continueAtNextSpontaneousStop = true;
1052
        notifyEngineRunAndInferiorRunOk();
1053
    } else if (newState == "enginerunandinferiorstopok")
hjk's avatar
hjk committed
1054
        notifyEngineRunAndInferiorStopOk();
1055
1056
1057
1058
1059
1060
1061
1062
    else if (newState == "inferiorshutdownok")
        notifyInferiorShutdownOk();
    else if (newState == "inferiorshutdownfailed")
        notifyInferiorShutdownFailed();
    else if (newState == "engineshutdownok")
        notifyEngineShutdownOk();
    else if (newState == "engineshutdownfailed")
        notifyEngineShutdownFailed();
hjk's avatar
hjk committed
1063
1064
    else if (newState == "inferiorexited")
        notifyInferiorExited();
1065
1066
}

1067
1068
void LldbEngine::refreshLocation(const GdbMi &reportedLocation)
{
1069
1070
1071
1072
1073
1074
1075
1076
1077
    if (debuggerCore()->boolSetting(OperateByInstruction)) {
        Location loc(reportedLocation["addr"].toAddress());
        loc.setNeedsMarker(true);
        gotoLocation(loc);
    } else {
        QString file = reportedLocation["file"].toUtf8();
        int line = reportedLocation["line"].toInt();
        gotoLocation(Location(file, line));
    }
1078
1079
}

1080
1081
void LldbEngine::reloadRegisters()
{
1082
1083
    if (debuggerCore()->isDockVisible(QLatin1String(DOCKWIDGET_REGISTER)))
        runCommand("reportRegisters");
1084
1085
}

1086
1087
void LldbEngine::fetchDisassembler(DisassemblerAgent *agent)
{
1088
1089
1090
1091
1092
1093
    QPointer<DisassemblerAgent> p(agent);
    int id = m_disassemblerAgents.value(p, -1);
    if (id == -1) {
        id = ++m_lastAgentId;
        m_disassemblerAgents.insert(p, id);
    }
hjk's avatar
hjk committed
1094
    runCommand(Command("disassemble").arg("cookie", id));
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
}


void LldbEngine::fetchMemory(MemoryAgent *agent, QObject *editorToken,
        quint64 addr, quint64 length)
{
    int id = m_memoryAgents.value(agent, -1);
    if (id == -1) {
        id = ++m_lastAgentId;
        m_memoryAgents.insert(agent, id);
    }
1106
    m_memoryAgentTokens.insert(id, editorToken);
1107
    runCommand(Command("fetchMemory")
hjk's avatar
hjk committed
1108
1109
1110
               .arg("address", addr)
               .arg("length", length)
               .arg("cookie", id));
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
}

void LldbEngine::changeMemory(MemoryAgent *agent, QObject *editorToken,
        quint64 addr, const QByteArray &data)
{
    int id = m_memoryAgents.value(agent, -1);
    if (id == -1) {
        id = ++m_lastAgentId;
        m_memoryAgents.insert(agent, id);
        m_memoryAgentTokens.insert(id, editorToken);
    }
hjk's avatar
hjk committed
1122
1123
1124
1125
    runCommand(Command("writeMemory")
               .arg("address", addr)
               .arg("data", data.toHex())
               .arg("cookie", id));
1126
1127
}

1128
1129
1130
void LldbEngine::setRegisterValue(int regnr, const QString &value)
{
    Register reg = registerHandler()->registers().at(regnr);
hjk's avatar
hjk committed
1131
    runCommand(Command("setRegister").arg("name", reg.name).arg("value", value));
1132
1133
1134
}


1135
1136
bool LldbEngine::hasCapability(unsigned cap) const
{
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
    if (cap & (ReverseSteppingCapability
        | AutoDerefPointersCapability
        | DisassemblerCapability
        | RegisterCapability
        | ShowMemoryCapability
        | JumpToLineCapability
        | ReloadModuleCapability
        | ReloadModuleSymbolsCapability
        | BreakOnThrowAndCatchCapability
        | BreakConditionCapability
        | TracePointCapability
        | ReturnFromFunctionCapability
        | CreateFullBacktraceCapability
        | WatchpointByAddressCapability
        | WatchpointByExpressionCapability
        | AddWatcherCapability
        | WatchWidgetsCapability
        | ShowModuleSymbolsCapability
        | ShowModuleSectionsCapability
        | CatchCapability
        | OperateByInstructionCapability
        | RunToLineCapability
        | WatchComplexExpressionsCapability
        | MemoryAddressCapability))
        return true;

    if (startParameters().startMode == AttachCore)
        return false;

    //return cap == SnapshotCapability;
    return false;
1168
1169
1170
1171
1172
1173
1174
}

DebuggerEngine *createLldbEngine(const DebuggerStartParameters &startParameters)
{
    return new LldbEngine(startParameters);
}

Fawzi Mohamed's avatar
Fawzi Mohamed committed
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
void LldbEngine::notifyEngineRemoteSetupDone(int portOrPid, int qmlPort)
{
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
    DebuggerEngine::notifyEngineRemoteSetupDone(portOrPid, qmlPort);

    if (qmlPort != -1)
        startParameters().qmlServerPort = qmlPort;
    if (portOrPid != -1) {
        if (startParameters().startMode == AttachExternal) {
            startParameters().attachPID = portOrPid;
        } else {
            QString &rc = startParameters().remoteChannel;
            const int sepIndex = rc.lastIndexOf(QLatin1Char(':'));
Fawzi Mohamed's avatar
Fawzi Mohamed committed
1188
            if (sepIndex != -1)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
                rc.replace(sepIndex + 1, rc.count() - sepIndex - 1,
                           QString::number(portOrPid));
        }
    }
    startLldb();
}

void LldbEngine::notifyEngineRemoteSetupFailed(const QString &reason)
{
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
    DebuggerEngine::notifyEngineRemoteSetupFailed(reason);
    showMessage(_("ADAPTER START FAILED"));
    if (!reason.isEmpty()) {
        const QString title = tr("Adapter start failed");
        Core::ICore::showWarningWithOptions(title, reason);
    }
    notifyEngineSetupFailed();
}
hjk's avatar
hjk committed
1207
1208
1209
1210
1211
1212
1213

///////////////////////////////////////////////////////////////////////
//
// Command
//
///////////////////////////////////////////////////////////////////////