cdbengine.cpp 119 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** 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.
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** 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
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29

30
#include "cdbengine.h"
hjk's avatar
hjk committed
31
32
33
34

#include "breakhandler.h"
#include "breakpoint.h"
#include "bytearrayinputstream.h"
35
36
#include "cdboptions.h"
#include "cdboptionspage.h"
hjk's avatar
hjk committed
37
#include "cdbparsehelpers.h"
38
39
#include "debuggeractions.h"
#include "debuggercore.h"
hjk's avatar
hjk committed
40
#include "debuggerinternalconstants.h"
41
#include "debuggerprotocol.h"
42
#include "debuggerrunner.h"
hjk's avatar
hjk committed
43
#include "debuggerstartparameters.h"
44
#include "debuggertooltipmanager.h"
hjk's avatar
hjk committed
45
46
47
48
49
50
51
52
53
#include "disassembleragent.h"
#include "disassemblerlines.h"
#include "memoryagent.h"
#include "moduleshandler.h"
#include "registerhandler.h"
#include "stackframe.h"
#include "stackhandler.h"
#include "threadshandler.h"
#include "watchhandler.h"
54
#include "watchutils.h"
55
#include "shared/cdbsymbolpathlisteditor.h"
56
#include "shared/hostutils.h"
57
#include "procinterrupt.h"
58
#include "sourceutils.h"
59

60
61
#include <TranslationUnit.h>

62
#include <coreplugin/icore.h>
63
#include <texteditor/itexteditor.h>
64
#include <projectexplorer/abi.h>
65
#include <projectexplorer/projectexplorerconstants.h>
66
67
#include <projectexplorer/task.h>
#include <projectexplorer/taskhub.h>
68

69
#include <utils/synchronousprocess.h>
70
#include <utils/qtcprocess.h>
71
72
73
#include <utils/winutils.h>
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
74
#include <utils/consoleprocess.h>
75
76
77
78
#include <utils/fileutils.h>

#include <cplusplus/findcdbbreakpoint.h>
#include <cplusplus/CppDocument.h>
79
#include <cpptools/ModelManagerInterface.h>
80

81
82
83
84
85
86
87
88
89
#include <QCoreApplication>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
#include <QTextStream>
#include <QDateTime>
#include <QToolTip>
#include <QMainWindow>
#include <QMessageBox>
90
91
92

#include <cctype>

93
94
Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgent*)
Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgent*)
95
96

enum { debug = 0 };
97
enum { debugLocals = 0 };
98
enum { debugSourceMapping = 0 };
99
enum { debugWatches = 0 };
100
101
enum { debugBreakpoints = 0 };

hjk's avatar
hjk committed
102
103
104
105
106
107
enum HandleLocalsFlags
{
    PartialLocalsUpdate = 0x1,
    LocalsUpdateForNewFrame = 0x2
};

108
#if 0
109
#  define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line);
110
#else
111
#  define STATE_DEBUG(state, func, line, notifyFunc)
112
113
#endif

114
115
116
117
118
119
120
121
/*!
    \class Debugger::Internal::CdbEngine

    Cdb engine version 2: Run the CDB process on pipes and parse its output.
    The engine relies on a CDB extension Qt Creator provides as an extension
    library (32/64bit), which is loaded into cdb.exe. It serves to:

    \list
122
    \li Notify the engine about the state of the debugging session:
123
        \list
124
125
126
127
        \li idle: (hooked up with .idle_cmd) debuggee stopped
        \li accessible: Debuggee stopped, cdb.exe accepts commands
        \li inaccessible: Debuggee runs, no way to post commands
        \li session active/inactive: Lost debuggee, terminating.
128
        \endlist
129
    \li Hook up with output/event callbacks and produce formatted output to be able
130
       to catch application output and exceptions.
131
    \li Provide some extension commands that produce output in a standardized (GDBMI)
132
133
      format that ends up in handleExtensionMessage(), for example:
      \list
134
135
136
137
      \li pid     Return debuggee pid for interrupting.
      \li locals  Print locals from SymbolGroup
      \li expandLocals Expand locals in symbol group
      \li registers, modules, threads
138
139
140
141
142
143
144
      \endlist
   \endlist

   Debugger commands can be posted by calling:

   \list

145
146
    \li postCommand(): Does not expect a reply
    \li postBuiltinCommand(): Run a builtin-command producing free-format, multiline output
147
148
       that is captured by enclosing it in special tokens using the 'echo' command and
       then invokes a callback with a CdbBuiltinCommand structure.
149
    \li postExtensionCommand(): Run a command provided by the extension producing
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
       one-line output and invoke a callback with a CdbExtensionCommand structure
       (output is potentially split up in chunks).
    \endlist


    Startup sequence:
    [Console: The console stub launches the process. On process startup,
              launchCDB() is called with AttachExternal].
    setupEngine() calls launchCDB() with the startparameters. The debuggee
    runs into the initial breakpoint (session idle). EngineSetupOk is
    notified (inferior still stopped). setupInferior() is then called
    which does breakpoint synchronization and issues the extension 'pid'
    command to obtain the inferior pid (which also hooks up the output callbacks).
     handlePid() notifies notifyInferiorSetupOk.
    runEngine() is then called which issues 'g' to continue the inferior.
    Shutdown mostly uses notifyEngineSpontaneousShutdown() as cdb just quits
    when the inferior exits (except attach modes).
*/
168

169
170
using namespace ProjectExplorer;

171
namespace Debugger {
172
namespace Internal {
173

174
175
static const char localsPrefixC[] = "local.";

hjk's avatar
hjk committed
176
177
struct MemoryViewCookie
{
178
    explicit MemoryViewCookie(MemoryAgent *a = 0, QObject *e = 0,
179
                              quint64 addr = 0, quint64 l = 0) :
hjk's avatar
hjk committed
180
181
        agent(a), editorToken(e), address(addr), length(l)
    {}
182

183
    MemoryAgent *agent;
184
185
186
187
188
    QObject *editorToken;
    quint64 address;
    quint64 length;
};

189
190
191
192
193
194
195
196
197
struct MemoryChangeCookie
{
    explicit MemoryChangeCookie(quint64 addr = 0, const QByteArray &d = QByteArray()) :
                               address(addr), data(d) {}

    quint64 address;
    QByteArray data;
};

198
199
struct ConditionalBreakPointCookie
{
200
201
    ConditionalBreakPointCookie(BreakpointModelId i = BreakpointModelId()) : id(i) {}
    BreakpointModelId id;
202
203
204
    GdbMi stopReason;
};

205
} // namespace Internal
206
207
} // namespace Debugger

208
Q_DECLARE_METATYPE(Debugger::Internal::MemoryViewCookie)
209
Q_DECLARE_METATYPE(Debugger::Internal::MemoryChangeCookie)
210
Q_DECLARE_METATYPE(Debugger::Internal::ConditionalBreakPointCookie)
211
212

namespace Debugger {
213
namespace Internal {
214

215
static inline bool isCreatorConsole(const DebuggerStartParameters &sp, const CdbOptions &o)
hjk's avatar
hjk committed
216
{
217
218
    return !o.cdbConsole && sp.useTerminal
           && (sp.startMode == StartInternal || sp.startMode == StartExternal);
hjk's avatar
hjk committed
219
}
220

hjk's avatar
hjk committed
221
222
static QMessageBox *
nonModalMessageBox(QMessageBox::Icon icon, const QString &title, const QString &text)
223
224
225
226
227
228
229
230
{
    QMessageBox *mb = new QMessageBox(icon, title, text, QMessageBox::Ok,
                                      debuggerCore()->mainWindow());
    mb->setAttribute(Qt::WA_DeleteOnClose);
    mb->show();
    return mb;
}

231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
// Base data structure for command queue entries with callback
struct CdbCommandBase
{
    typedef CdbEngine::BuiltinCommandHandler CommandHandler;

    CdbCommandBase();
    CdbCommandBase(const QByteArray  &cmd, int token, unsigned flags,
                   unsigned nc, const QVariant &cookie);

    int token;
    unsigned flags;
    QByteArray command;
    QVariant cookie;
    // Continue with another commands as specified in CommandSequenceFlags
    unsigned commandSequence;
};

CdbCommandBase::CdbCommandBase() :
    token(0), flags(0), commandSequence(0)
{
}

CdbCommandBase::CdbCommandBase(const QByteArray  &cmd, int t, unsigned f,
                               unsigned nc, const QVariant &c) :
    token(t), flags(f), command(cmd), cookie(c), commandSequence(nc)
{
}

// Queue entry for builtin commands producing free-format
// line-by-line output.
struct CdbBuiltinCommand : public CdbCommandBase
{
    typedef CdbEngine::BuiltinCommandHandler CommandHandler;

    CdbBuiltinCommand() {}
    CdbBuiltinCommand(const QByteArray  &cmd, int token, unsigned flags,
                      CommandHandler h,
                      unsigned nc, const QVariant &cookie) :
hjk's avatar
hjk committed
269
270
        CdbCommandBase(cmd, token, flags, nc, cookie), handler(h)
    {}
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332


    QByteArray joinedReply() const;

    CommandHandler handler;
    QList<QByteArray> reply;
};

QByteArray CdbBuiltinCommand::joinedReply() const
{
    if (reply.isEmpty())
        return QByteArray();
    QByteArray answer;
    answer.reserve(120  * reply.size());
    foreach (const QByteArray &l, reply) {
        answer += l;
        answer += '\n';
    }
    return answer;
}

// Queue entry for Qt Creator extension commands producing one-line
// output with success flag and error message.
struct CdbExtensionCommand : public CdbCommandBase
{
    typedef CdbEngine::ExtensionCommandHandler CommandHandler;

    CdbExtensionCommand() : success(false) {}
    CdbExtensionCommand(const QByteArray  &cmd, int token, unsigned flags,
                      CommandHandler h,
                      unsigned nc, const QVariant &cookie) :
        CdbCommandBase(cmd, token, flags, nc, cookie), handler(h),success(false) {}

    CommandHandler handler;
    QByteArray reply;
    QByteArray errorMessage;
    bool success;
};

template <class CommandPtrType>
int indexOfCommand(const QList<CommandPtrType> &l, int token)
{
    const int count = l.size();
    for (int i = 0; i < count; i++)
        if (l.at(i)->token == token)
            return i;
    return -1;
}

static inline bool validMode(DebuggerStartMode sm)
{
    switch (sm) {
    case NoStartMode:
    case StartRemoteGdb:
        return false;
    default:
        break;
    }
    return true;
}

// Accessed by RunControlFactory
333
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp, QString *errorMessage)
334
335
336
{
#ifdef Q_OS_WIN
    CdbOptionsPage *op = CdbOptionsPage::instance();
337
338
    if (!op || !op->options()->isValid() || !validMode(sp.startMode)) {
        *errorMessage = QLatin1String("Internal error: Invalid start parameters passed for thre CDB engine.");
339
340
        return 0;
    }
341
    return new CdbEngine(sp, op->options());
342
343
344
#else
    Q_UNUSED(sp)
#endif
345
    *errorMessage = QString::fromLatin1("Unsupported debug mode");
346
347
348
    return 0;
}

349
void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
350
{
351
#ifdef Q_OS_WIN
352
    opts->push_back(new CdbOptionsPage);
353
354
355
#else
    Q_UNUSED(opts);
#endif
356
357
358
359
360
361
}

#define QT_CREATOR_CDB_EXT "qtcreatorcdbext"

static inline Utils::SavedAction *theAssemblerAction()
{
362
    return debuggerCore()->action(OperateByInstruction);
363
364
}

365
366
CdbEngine::CdbEngine(const DebuggerStartParameters &sp, const OptionsPtr &options) :
    DebuggerEngine(sp),
367
368
369
    m_creatorExtPrefix("<qtcreatorcdbext>|"),
    m_tokenPrefix("<token>"),
    m_options(options),
370
    m_effectiveStartMode(NoStartMode),
371
372
373
374
    m_accessible(false),
    m_specialStopMode(NoSpecialStop),
    m_nextCommandToken(0),
    m_currentBuiltinCommandIndex(-1),
hjk's avatar
hjk committed
375
    m_extensionCommandPrefixBA("!" QT_CREATOR_CDB_EXT "."),
376
377
378
379
    m_operateByInstructionPending(true),
    m_operateByInstruction(true), // Default CDB setting
    m_notifyEngineShutdownOnTermination(false),
    m_hasDebuggee(false),
380
    m_cdbIs64Bit(false),
381
    m_elapsedLogTime(0),
382
    m_sourceStepInto(false),
383
    m_watchPointX(0),
384
385
    m_watchPointY(0),
    m_ignoreCdbOutput(false)
386
{
387
    connect(theAssemblerAction(), SIGNAL(triggered(bool)), this, SLOT(operateByInstructionTriggered(bool)));
388
389
390
391
392
393
394
395

    setObjectName(QLatin1String("CdbEngine"));
    connect(&m_process, SIGNAL(finished(int)), this, SLOT(processFinished()));
    connect(&m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError()));
    connect(&m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOut()));
    connect(&m_process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardOut()));
}

396
397
398
void CdbEngine::init()
{
    m_effectiveStartMode = NoStartMode;
399
    notifyInferiorPid(0);
400
401
402
403
    m_accessible = false;
    m_specialStopMode = NoSpecialStop;
    m_nextCommandToken  = 0;
    m_currentBuiltinCommandIndex = -1;
404
    m_operateByInstructionPending = theAssemblerAction()->isChecked();
405
406
407
408
409
410
    m_operateByInstruction = true; // Default CDB setting
    m_notifyEngineShutdownOnTermination = false;
    m_hasDebuggee = false;
    m_sourceStepInto = false;
    m_watchPointX = m_watchPointY = 0;
    m_ignoreCdbOutput = false;
411
    m_watchInameToName.clear();
412
413
414
415
416
417

    m_outputBuffer.clear();
    m_builtinCommandQueue.clear();
    m_extensionCommandQueue.clear();
    m_extensionMessageBuffer.clear();
    m_pendingBreakpointMap.clear();
418
    m_customSpecialStopData.clear();
419
    m_symbolAddressCache.clear();
420
    m_coreStopReason.reset();
421
422
423
424
425
426
427
428
429
430
431
432
433

    // Create local list of mappings in native separators
    m_sourcePathMappings.clear();
    const QSharedPointer<GlobalDebuggerOptions> globalOptions = debuggerCore()->globalDebuggerOptions();
    if (!globalOptions->sourcePathMap.isEmpty()) {
        typedef GlobalDebuggerOptions::SourcePathMap::const_iterator SourcePathMapIterator;
        m_sourcePathMappings.reserve(globalOptions->sourcePathMap.size());
        const SourcePathMapIterator cend = globalOptions->sourcePathMap.constEnd();
        for (SourcePathMapIterator it = globalOptions->sourcePathMap.constBegin(); it != cend; ++it) {
            m_sourcePathMappings.push_back(SourcePathMapping(QDir::toNativeSeparators(it.key()),
                                                             QDir::toNativeSeparators(it.value())));
        }
    }
434
435
    // update source path maps from debugger start params
    mergeStartParametersSourcePathMap();
436
    QTC_ASSERT(m_process.state() != QProcess::Running, Utils::SynchronousProcess::stopProcess(m_process));
437
438
}

439
440
441
442
443
444
CdbEngine::~CdbEngine()
{
}

void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
{
445
446
447
    // To be set next time session becomes accessible
    m_operateByInstructionPending = operateByInstruction;
    if (state() == InferiorStopOk)
448
449
450
451
452
        syncOperateByInstruction(operateByInstruction);
}

void CdbEngine::syncOperateByInstruction(bool operateByInstruction)
{
453
454
    if (debug)
        qDebug("syncOperateByInstruction current: %d new %d", m_operateByInstruction, operateByInstruction);
455
456
    if (m_operateByInstruction == operateByInstruction)
        return;
457
    QTC_ASSERT(m_accessible, return);
458
459
460
    m_operateByInstruction = operateByInstruction;
    postCommand(m_operateByInstruction ? QByteArray("l-t") : QByteArray("l+t"), 0);
    postCommand(m_operateByInstruction ? QByteArray("l-s") : QByteArray("l+s"), 0);
461
462
}

463
bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
464
465
                                     TextEditor::ITextEditor *editor,
                                     const DebuggerToolTipContext &contextIn)
466
{
467
468
469
470
    if (debug)
        qDebug() << Q_FUNC_INFO;
    // Need a stopped debuggee and a cpp file in a valid frame
    if (state() != InferiorStopOk || !isCppEditor(editor) || stackHandler()->currentIndex() < 0)
471
        return false;
472
473
474
    // Determine expression and function
    int line;
    int column;
475
    DebuggerToolTipContext context = contextIn;
476
    QString exp = fixCppExpression(cppExpressionAt(editor, context.position, &line, &column, &context.function));
477
    // Are we in the current stack frame
478
    if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function)
479
        return false;
480
481
482
    // Show tooltips of local variables only. Anything else can slow debugging down.
    const WatchData *localVariable = watchHandler()->findCppLocalVariable(exp);
    if (!localVariable)
483
        return false;
484
    DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
485
    tw->setContext(context);
486
    tw->setIname(localVariable->iname);
487
    tw->acquireEngine(this);
488
    DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw);
489
    return true;
490
491
492
}

// Determine full path to the CDB extension library.
493
QString CdbEngine::extensionLibraryName(bool is64Bit)
494
495
496
497
{
    // Determine extension lib name and path to use
    QString rc;
    QTextStream(&rc) << QFileInfo(QCoreApplication::applicationDirPath()).path()
hjk's avatar
hjk committed
498
                     << "/lib/" << (is64Bit ? QT_CREATOR_CDB_EXT "64" : QT_CREATOR_CDB_EXT "32")
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
                     << '/' << QT_CREATOR_CDB_EXT << ".dll";
    return rc;
}

// Determine environment for CDB.exe, start out with run config and
// add CDB extension path merged with system value should there be one.
static QStringList mergeEnvironment(QStringList runConfigEnvironment,
                                    QString cdbExtensionPath)
{
    // Determine CDB extension path from Qt Creator
    static const char cdbExtensionPathVariableC[] = "_NT_DEBUGGER_EXTENSION_PATH";
    const QByteArray oldCdbExtensionPath = qgetenv(cdbExtensionPathVariableC);
    if (!oldCdbExtensionPath.isEmpty()) {
        cdbExtensionPath.append(QLatin1Char(';'));
        cdbExtensionPath.append(QString::fromLocal8Bit(oldCdbExtensionPath));
    }
    // We do not assume someone sets _NT_DEBUGGER_EXTENSION_PATH in the run
    // config, just to make sure, delete any existing entries
    const QString cdbExtensionPathVariableAssign =
            QLatin1String(cdbExtensionPathVariableC) + QLatin1Char('=');
    for (QStringList::iterator it = runConfigEnvironment.begin(); it != runConfigEnvironment.end() ; ) {
        if (it->startsWith(cdbExtensionPathVariableAssign)) {
            it = runConfigEnvironment.erase(it);
            break;
        } else {
            ++it;
        }
    }
    runConfigEnvironment.append(cdbExtensionPathVariableAssign +
                                QDir::toNativeSeparators(cdbExtensionPath));
    return runConfigEnvironment;
}

int CdbEngine::elapsedLogTime() const
{
    const int elapsed = m_logTime.elapsed();
    const int delta = elapsed - m_elapsedLogTime;
    m_elapsedLogTime = elapsed;
    return delta;
}

540
541
542
543
544
545
546
// Start the console stub with the sub process. Continue in consoleStubProcessStarted.
bool CdbEngine::startConsole(const DebuggerStartParameters &sp, QString *errorMessage)
{
    if (debug)
        qDebug("startConsole %s", qPrintable(sp.executable));
    m_consoleStub.reset(new Utils::ConsoleProcess);
    m_consoleStub->setMode(Utils::ConsoleProcess::Suspend);
547
548
    connect(m_consoleStub.data(), SIGNAL(processError(QString)),
            SLOT(consoleStubError(QString)));
549
550
    connect(m_consoleStub.data(), SIGNAL(processStarted()),
            SLOT(consoleStubProcessStarted()));
551
    connect(m_consoleStub.data(), SIGNAL(stubStopped()),
552
553
            SLOT(consoleStubExited()));
    m_consoleStub->setWorkingDirectory(sp.workingDirectory);
554
555
    if (sp.environment.size())
        m_consoleStub->setEnvironment(sp.environment);
556
557
558
559
560
561
562
    if (!m_consoleStub->start(sp.executable, sp.processArgs)) {
        *errorMessage = tr("The console process '%1' could not be started.").arg(sp.executable);
        return false;
    }
    return true;
}

563
void CdbEngine::consoleStubError(const QString &msg)
564
{
565
    if (debug)
566
567
568
569
        qDebug("consoleStubProcessMessage() in %s %s", stateName(state()), qPrintable(msg));
    if (state() == EngineSetupRequested) {
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
570
    } else {
571
572
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
        notifyEngineIll();
573
    }
574
    nonModalMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg);
575
576
577
578
579
580
581
582
583
584
585
586
}

void CdbEngine::consoleStubProcessStarted()
{
    if (debug)
        qDebug("consoleStubProcessStarted() PID=%lld", m_consoleStub->applicationPID());
    // Attach to console process.
    DebuggerStartParameters attachParameters = startParameters();
    attachParameters.executable.clear();
    attachParameters.processArgs.clear();
    attachParameters.attachPID = m_consoleStub->applicationPID();
    attachParameters.startMode = AttachExternal;
587
    attachParameters.useTerminal = false;
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
    showMessage(QString::fromLatin1("Attaching to %1...").arg(attachParameters.attachPID), LogMisc);
    QString errorMessage;
    if (!launchCDB(attachParameters, &errorMessage)) {
        showMessage(errorMessage, LogError);
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
    }
}

void CdbEngine::consoleStubExited()
{
}

void CdbEngine::setupEngine()
{
    if (debug)
        qDebug(">setupEngine");
    // Nag to add symbol server
    if (CdbSymbolPathListEditor::promptToAddSymbolServer(CdbOptions::settingsGroup(),
                                                         &(m_options->symbolPaths)))
hjk's avatar
hjk committed
608
        m_options->toSettings(Core::ICore::settings());
609

610
611
612
    init();
    if (!m_logTime.elapsed())
        m_logTime.start();
613
614
615
616
617
618
    QString errorMessage;
    // Console: Launch the stub with the suspended application and attach to it
    // CDB in theory has a command line option '-2' that launches a
    // console, too, but that immediately closes when the debuggee quits.
    // Use the Creator stub instead.
    const DebuggerStartParameters &sp = startParameters();
619
    const bool launchConsole = isCreatorConsole(sp, *m_options);
620
621
622
623
624
625
626
627
628
629
630
    m_effectiveStartMode = launchConsole ? AttachExternal : sp.startMode;
    const bool ok = launchConsole ?
                startConsole(startParameters(), &errorMessage) :
                launchCDB(startParameters(), &errorMessage);
    if (debug)
        qDebug("<setupEngine ok=%d", ok);
    if (!ok) {
        showMessage(errorMessage, LogError);
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
    }
631
    const QString normalFormat = tr("Normal");
632
    const QStringList stringFormats = QStringList()
633
        << normalFormat << tr("Separate Window");
634
635
636
637
638
    WatchHandler *wh = watchHandler();
    wh->addTypeFormats("QString", stringFormats);
    wh->addTypeFormats("QString *", stringFormats);
    wh->addTypeFormats("QByteArray", stringFormats);
    wh->addTypeFormats("QByteArray *", stringFormats);
639
    wh->addTypeFormats("std__basic_string", stringFormats);  // Python dumper naming convention for std::[w]string
640
641
642
643
    const QStringList imageFormats = QStringList()
        << normalFormat << tr("Image");
    wh->addTypeFormats("QImage", imageFormats);
    wh->addTypeFormats("QImage *", imageFormats);
644
645
646
647
648
649
}

bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessage)
{
    if (debug)
        qDebug("launchCDB startMode=%d", sp.startMode);
650
    const QChar blank(QLatin1Char(' '));
651
    // Start engine which will run until initial breakpoint:
652
    // Determine binary (force MSVC), extension lib name and path to use
653
654
    // The extension is passed as relative name with the path variable set
    //(does not work with absolute path names)
hjk's avatar
hjk committed
655
    const QString executable = sp.debuggerCommand;
656
657
658
659
660
    if (executable.isEmpty()) {
        *errorMessage = tr("There is no CDB executable specified.");
        return false;
    }

661
    m_cdbIs64Bit =
662
663
664
665
666
#ifdef Q_OS_WIN
            Utils::winIs64BitBinary(executable);
#else
            false;
#endif
667
    const QFileInfo extensionFi(CdbEngine::extensionLibraryName(m_cdbIs64Bit));
668
669
670
671
672
    if (!extensionFi.isFile()) {
        *errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found.").
                arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
        return false;
    }
673
    const QString extensionFileName = extensionFi.fileName();
674
675
    // Prepare arguments
    QStringList arguments;
676
    const bool isRemote = sp.startMode == AttachToRemoteServer;
677
678
679
680
681
    if (isRemote) { // Must be first
        arguments << QLatin1String("-remote") << sp.remoteChannel;
    } else {
        arguments << (QLatin1String("-a") + extensionFileName);
    }
682
683
684
685
    // Source line info/No terminal breakpoint / Pull extension
    arguments << QLatin1String("-lines") << QLatin1String("-G")
    // register idle (debuggee stop) notification
              << QLatin1String("-c")
686
              << QLatin1String(".idle_cmd ") + QString::fromLatin1(m_extensionCommandPrefixBA) + QLatin1String("idle");
687
688
    if (sp.useTerminal) // Separate console
        arguments << QLatin1String("-2");
689
690
    if (m_options->ignoreFirstChanceAccessViolation)
        arguments << QLatin1String("-x");
691
692
693
694
    if (!m_options->symbolPaths.isEmpty())
        arguments << QLatin1String("-y") << m_options->symbolPaths.join(QString(QLatin1Char(';')));
    if (!m_options->sourcePaths.isEmpty())
        arguments << QLatin1String("-srcpath") << m_options->sourcePaths.join(QString(QLatin1Char(';')));
695
696
    // Compile argument string preserving quotes
    QString nativeArguments = m_options->additionalArguments;
697
698
699
    switch (sp.startMode) {
    case StartInternal:
    case StartExternal:
700
701
        if (!nativeArguments.isEmpty())
            nativeArguments.push_back(blank);
702
703
        Utils::QtcProcess::addArgs(&nativeArguments,
                                   QStringList(QDir::toNativeSeparators(sp.executable)));
704
        break;
705
    case AttachToRemoteServer:
706
        break;
707
    case AttachExternal:
708
    case AttachCrashedExternal:
709
        arguments << QLatin1String("-p") << QString::number(sp.attachPID);
710
        if (sp.startMode == AttachCrashedExternal) {
711
            arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g");
712
        } else {
713
            if (isCreatorConsole(startParameters(), *m_options))
714
715
                arguments << QLatin1String("-pr") << QLatin1String("-pb");
        }
716
        break;
717
718
719
    case AttachCore:
        arguments << QLatin1String("-z") << sp.coreFile;
        break;
720
721
722
723
    default:
        *errorMessage = QString::fromLatin1("Internal error: Unsupported start mode %1.").arg(sp.startMode);
        return false;
    }
724
725
726
727
728
729
    if (!sp.processArgs.isEmpty()) { // Complete native argument string.
        if (!nativeArguments.isEmpty())
            nativeArguments.push_back(blank);
        nativeArguments += sp.processArgs;
    }

730
731
    const QString msg = QString::fromLatin1("Launching %1 %2\nusing %3 of %4.").
            arg(QDir::toNativeSeparators(executable),
732
                arguments.join(QString(blank)) + blank + nativeArguments,
733
734
735
736
737
                QDir::toNativeSeparators(extensionFi.absoluteFilePath()),
                extensionFi.lastModified().toString(Qt::SystemLocaleShortDate));
    showMessage(msg, LogMisc);

    m_outputBuffer.clear();
738
739
740
741
    const QStringList environment = sp.environment.size() == 0 ?
                                    QProcessEnvironment::systemEnvironment().toStringList() :
                                    sp.environment.toStringList();
    m_process.setEnvironment(mergeEnvironment(environment, extensionFi.absolutePath()));
742
743
    if (!sp.workingDirectory.isEmpty())
        m_process.setWorkingDirectory(sp.workingDirectory);
744

745
#ifdef Q_OS_WIN
746
747
    if (!nativeArguments.isEmpty()) // Appends
        m_process.setNativeArguments(nativeArguments);
748
#endif
749
750
751
752
753
754
755
756
757
758
759
760
761
762
    m_process.start(executable, arguments);
    if (!m_process.waitForStarted()) {
        *errorMessage = QString::fromLatin1("Internal error: Cannot start process %1: %2").
                arg(QDir::toNativeSeparators(executable), m_process.errorString());
        return false;
    }
#ifdef Q_OS_WIN
    const unsigned long pid = Utils::winQPidToPid(m_process.pid());
#else
    const unsigned long pid = 0;
#endif
    showMessage(QString::fromLatin1("%1 running as %2").
                arg(QDir::toNativeSeparators(executable)).arg(pid), LogMisc);
    m_hasDebuggee = true;
763
764
765
766
767
    if (isRemote) { // We do not get an 'idle' in a remote session, but are accessible
        m_accessible = true;
        const QByteArray loadCommand = QByteArray(".load ")
                + extensionFileName.toLocal8Bit();
        postCommand(loadCommand, 0);
768
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk")
769
770
        notifyEngineSetupOk();
    }
771
772
773
774
775
    return true;
}

void CdbEngine::setupInferior()
{
776
777
    if (debug)
        qDebug("setupInferior");
778
779
780
781
782
783
    // QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
    // (attemptBreakpointSynchronization() will be directly called then)
    attemptBreakpointSynchronization();
    if (startParameters().breakOnMain) {
        const BreakpointParameters bp(BreakpointAtMain);
        postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings,
784
                                            BreakpointModelId(quint16(-1)), true), 0);
785
    }
786
    postCommand("sxn 0x4000001f", 0); // Do not break on WowX86 exceptions.
787
    postCommand(".asm source_line", 0); // Source line in assembly
788
789
790
791
792
    postCommand(m_extensionCommandPrefixBA + "setparameter maxStringLength="
                + debuggerCore()->action(MaximalStringLength)->value().toByteArray()
                + " maxStackDepth="
                + debuggerCore()->action(MaximalStackDepth)->value().toByteArray()
                , 0);
793
794
795
    postExtensionCommand("pid", QByteArray(), 0, &CdbEngine::handlePid);
}

796
797
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
static QByteArray msvcRunTime(const Abi::OSFlavor flavour)
{
    switch (flavour)  {
    case Abi::WindowsMsvc2005Flavor:
        return "MSVCR80";
    case Abi::WindowsMsvc2008Flavor:
        return "MSVCR90";
    case Abi::WindowsMsvc2010Flavor:
        return "MSVCR100";
    case Abi::WindowsMsvc2012Flavor:
        return "MSVCR110"; // #FIXME: VS2012 beta, will probably be 12 in final?
    default:
        break;
    }
    return "MSVCRT"; // MinGW, others.
}

static QByteArray breakAtFunctionCommand(const QByteArray &function,
                                         const QByteArray &module = QByteArray())
{
     QByteArray result = "bu ";
     if (!module.isEmpty()) {
         result += module;
         result += '!';
     }
     result += function;
     return result;
}

825
826
void CdbEngine::runEngine()
{
827
828
    if (debug)
        qDebug("runEngine");
829
    foreach (const QString &breakEvent, m_options->breakEvents)
830
            postCommand(QByteArray("sxe ") + breakEvent.toLatin1(), 0);
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
    // Break functions: each function must be fully qualified,
    // else the debugger will slow down considerably.
    foreach (const QString &breakFunctionS, m_options->breakFunctions) {
        const QByteArray breakFunction = breakFunctionS.toLatin1();
        if (breakFunction == CdbOptions::crtDbgReport) {
            // CrtDbgReport(): Add MSVC runtime (debug, release)
            // and stop at Wide character version as well
            const QByteArray module = msvcRunTime(startParameters().toolChainAbi.osFlavor());
            const QByteArray debugModule = module + 'D';
            const QByteArray wideFunc = breakFunction + 'W';
            postCommand(breakAtFunctionCommand(breakFunction, module), 0);
            postCommand(breakAtFunctionCommand(wideFunc, module), 0);
            postCommand(breakAtFunctionCommand(breakFunction, debugModule), 0);
            postCommand(breakAtFunctionCommand(wideFunc, debugModule), 0);
        } else {
            postCommand(breakAtFunctionCommand(breakFunction), 0);
        }
    }
849
850
851
852
853
854
855
856
    if (debuggerCore()->boolSetting(BreakOnWarning)) {
        postCommand("bm /( QtCored4!qWarning", 0); // 'bm': All overloads.
        postCommand("bm /( Qt5Cored!QMessageLogger::warning", 0);
    }
    if (debuggerCore()->boolSetting(BreakOnFatal)) {
        postCommand("bm /( QtCored4!qFatal", 0); // 'bm': All overloads.
        postCommand("bm /( Qt5Cored!QMessageLogger::fatal", 0);
    }
857
858
859
860
861
862
863
    if (startParameters().startMode == AttachCore) {
        QTC_ASSERT(!m_coreStopReason.isNull(), return; );
        notifyInferiorUnrunnable();
        processStop(*m_coreStopReason, false);
    } else {
        postCommand("g", 0);
    }
864
865
}

866
867
868
869
870
bool CdbEngine::commandsPending() const
{
    return !m_builtinCommandQueue.isEmpty() || !m_extensionCommandQueue.isEmpty();
}

871
872
873
874
875
876
877
878
879
void CdbEngine::shutdownInferior()
{
    if (debug)
        qDebug("CdbEngine::shutdownInferior in state '%s', process running %d", stateName(state()),
               isCdbProcessRunning());

    if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
        if (debug)
            qDebug("notifyInferiorShutdownOk");
880
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
881
882
883
        notifyInferiorShutdownOk();
        return;
    }
884

885
886
    if (m_accessible) { // except console.
        if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
887
            detachDebugger();
888
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
889
890
        notifyInferiorShutdownOk();
    } else {
891
892
893
894
895
896
897
898
899
900
901
902
903
        // A command got stuck.
        if (commandsPending()) {
            showMessage(QLatin1String("Cannot shut down inferior due to pending commands."), LogWarning);
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownFailed")
            notifyInferiorShutdownFailed();
            return;
        }
        if (!canInterruptInferior()) {
            showMessage(QLatin1String("Cannot interrupt the inferior."), LogWarning);
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownFailed")
            notifyInferiorShutdownFailed();
            return;
        }
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
        interruptInferior(); // Calls us again
    }
}

/* shutdownEngine/processFinished:
 * Note that in the case of launching a process by the debugger, the debugger
 * automatically quits a short time after reporting the session becoming
 * inaccessible without debuggee (notifyInferiorExited). In that case,
 * processFinished() must not report any arbitrarily notifyEngineShutdownOk()
 * as not to confuse the state engine.
 */

void CdbEngine::shutdownEngine()
{
    if (debug)
919
920
921
922
        qDebug("CdbEngine::shutdownEngine in state '%s', process running %d,"
               "accessible=%d,commands pending=%d",
               stateName(state()), isCdbProcessRunning(), m_accessible,
               commandsPending());
923
924

    if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
925
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
926
927
928
929
        notifyEngineShutdownOk();
        return;
    }

930
    // No longer trigger anything from messages
931
    m_ignoreCdbOutput = true;
932
933
    // Go for kill if there are commands pending.
    if (m_accessible && !commandsPending()) {
934
935
        // detach (except console): Wait for debugger to finish.
        if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
936
            detachDebugger();
937
        // Remote requires a bit more force to quit.
938
        if (m_effectiveStartMode == AttachToRemoteServer) {
939
940
941
942
943
944
945
946
947
            postCommand(m_extensionCommandPrefixBA + "shutdownex", 0);
            postCommand("qq", 0);
        } else {
            postCommand("q", 0);
        }
        m_notifyEngineShutdownOnTermination = true;
        return;
    } else {
        // Remote process. No can do, currently
948
        m_notifyEngineShutdownOnTermination = true;
949
        Utils::SynchronousProcess::stopProcess(m_process);
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
        return;
    }
    // Lost debuggee, debugger should quit anytime now
    if (!m_hasDebuggee) {
        m_notifyEngineShutdownOnTermination = true;
        return;
    }
    interruptInferior();
}

void CdbEngine::processFinished()
{
    if (debug)
        qDebug("CdbEngine::processFinished %dms '%s' notify=%d (exit state=%d, ex=%d)",
               elapsedLogTime(), stateName(state()), m_notifyEngineShutdownOnTermination,
               m_process.exitStatus(), m_process.exitCode());

    const bool crashed = m_process.exitStatus() == QProcess::CrashExit;
968
    if (crashed)
969
        showMessage(tr("CDB crashed"), LogError); // not in your life.
970
    else
971
972
973
974
975
976
        showMessage(tr("CDB exited (%1)").arg(m_process.exitCode()), LogMisc);

    if (m_notifyEngineShutdownOnTermination) {
        if (crashed) {
            if (debug)
                qDebug("notifyEngineIll");
977
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
978
979
            notifyEngineIll();
        } else {
980
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
981
982
983
            notifyEngineShutdownOk();
        }
    } else {
984
985
986
987
988
989
990
991
992
        // The QML/CPP engine relies on the standard sequence of InferiorShutDown,etc.
        // Otherwise, we take a shortcut.
        if (isSlaveEngine()) {
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorExited")
            notifyInferiorExited();
        } else {
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSpontaneousShutdown")
            notifyEngineSpontaneousShutdown();
        }
993
994
995
996
997
998
999
1000
    }
}

void CdbEngine::detachDebugger()
{
    postCommand(".detach", 0);
}

1001
1002
1003
1004
1005
static inline bool isWatchIName(const QByteArray &iname)
{
    return iname.startsWith("watch");
}

1006
1007
void CdbEngine::updateWatchData(const WatchData &dataIn,
                                const WatchUpdateFlags & flags)
1008
{
1009
1010
1011
    if (debug || debugLocals || debugWatches)
        qDebug("CdbEngine::updateWatchData() %dms accessible=%d %s incr=%d: %s",
               elapsedLogTime(), m_accessible, stateName(state()),
1012
1013
1014
               flags.tryIncremental,
               qPrintable(dataIn.toString()));

1015
1016
1017
1018
1019
1020
1021
1022
    if (!m_accessible) // Add watch data while running?
        return;

    // New watch item?
    if (isWatchIName(dataIn.iname) && dataIn.isValueNeeded()) {
        QByteArray args;
        ByteArrayInputStream str(args);
        str << dataIn.iname << " \"" << dataIn.exp << '"';
1023
1024
1025
1026
        // Store the name since the CDB extension library
        // does not maintain the names of watches.
        if (!dataIn.name.isEmpty() && dataIn.name != QLatin1String(dataIn.exp))
            m_watchInameToName.insert(dataIn.iname, dataIn.name);
1027
1028
1029
1030
1031
1032
1033
        postExtensionCommand("addwatch", args, 0,
                             &CdbEngine::handleAddWatch, 0,
                             qVariantFromValue(dataIn));
        return;
    }

    if (!dataIn.hasChildren && !dataIn.isValueNeeded()) {
1034
        WatchData data = dataIn;
1035
1036
1037
1038
1039
1040
1041
        data.setAllUnneeded();
        watchHandler()->insertData(data);
        return;
    }
    updateLocalVariable(dataIn.iname);
}

1042
1043
1044
1045
1046
1047
1048
1049
1050
void CdbEngine::handleAddWatch(const CdbExtensionCommandPtr &reply)
{
    WatchData item = qvariant_cast<WatchData>(reply->cookie);
    if (debugWatches)
        qDebug() << "handleAddWatch ok="  << reply->success << item.iname;
    if (reply->success) {
        updateLocalVariable(item.iname);
    } else {
        item.setError(tr("Unable to add expression"));
hjk's avatar
hjk committed
1051
        watchHandler()->insertIncompleteData(item);
1052
        showMessage(QString::fromLatin1("Unable to add watch item '%1'/'%2': %3").
1053
                    arg(QString::fromLatin1(item.iname), QString::fromLatin1(item.exp),
1054
                        QString::fromLocal8Bit(reply->errorMessage)), LogError);
1055
1056
1057
    }
}

1058
1059
void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const
{
1060
1061
    if (debuggerCore()->boolSetting(VerboseLog))
        str << blankSeparator << "-v";
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
    if (debuggerCore()->boolSetting(UseDebuggingHelpers))
        str << blankSeparator << "-c";
    const QByteArray typeFormats = watchHandler()->typeFormatRequests();
    if (!typeFormats.isEmpty())
        str << blankSeparator << "-T " << typeFormats;
    const QByteArray individualFormats = watchHandler()->individualFormatRequests();
    if (!individualFormats.isEmpty())
        str << blankSeparator << "-I " << individualFormats;
}

1072
1073
void CdbEngine::updateLocalVariable(const QByteArray &iname)
{
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
    const bool isWatch = isWatchIName(iname);
    if (debugWatches)
        qDebug() << "updateLocalVariable watch=" << isWatch << iname;
    QByteArray localsArguments;
    ByteArrayInputStream str(localsArguments);
    addLocalsOptions(str);
    if (!isWatch) {
        const int stackFrame = stackHandler()->currentIndex();
        if (stackFrame < 0) {
            qWarning("Internal error; no stack frame in updateLocalVariable");
            return;
        }
        str << blankSeparator << stackFrame;
1087
    }
1088
    str << blankSeparator << iname;
hjk's avatar
hjk committed
1089
1090
1091
1092
    postExtensionCommand(isWatch ? "watches" : "locals",
                         localsArguments, 0,
                         &CdbEngine::handleLocals,
                         0, QVariant(int(PartialLocalsUpdate)));
1093
1094
}

hjk's avatar
hjk committed
1095
bool CdbEngine::hasCapability(unsigned cap) const
1096
{
hjk's avatar
hjk committed
1097
1098
    return cap & (DisassemblerCapability | RegisterCapability
           | ShowMemoryCapability
1099
           |WatchpointByAddressCapability|JumpToLineCapability|AddWatcherCapability|WatchWidgetsCapability
1100
           |ReloadModuleCapability
1101
           |BreakOnThrowAndCatchCapability // Sort-of: Can break on throw().
1102
           |BreakConditionCapability|TracePointCapability
1103
1104
           |BreakModuleCapability
           |OperateByInstructionCapability
1105
           |RunToLineCapability
hjk's avatar
hjk committed
1106
           |MemoryAddressCapability);
1107
1108
1109
1110
}

void CdbEngine::executeStep()
{
1111
1112
    if (!m_operateByInstruction)
        m_sourceStepInto = true; // See explanation at handleStackTrace().
1113
    postCommand(QByteArray("t"), 0); // Step into-> t (trace)
1114
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
1115
1116
1117
1118
1119
1120
    notifyInferiorRunRequested();
}

void CdbEngine::executeStepOut()
{
    postCommand(QByteArray("gu"), 0); // Step out-> gu (go up)
1121
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
1122
1123
1124
1125
1126
1127
    notifyInferiorRunRequested();
}

void CdbEngine::executeNext()
{
    postCommand(QByteArray("p"), 0); // Step over -> p
1128
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
    notifyInferiorRunRequested();
}

void CdbEngine::executeStepI()
{
    executeStep();
}

void CdbEngine::executeNextI()
{
    executeNext();
}

void CdbEngine::continueInferior()
{
1144
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
1145
1146
1147
1148
1149
1150
1151
1152
1153
    notifyInferiorRunRequested();
    doContinueInferior();
}

void CdbEngine::doContinueInferior()
{
    postCommand(QByteArray("g"), 0);
}

1154
1155
bool CdbEngine::canInterruptInferior() const
{
1156
    return m_effectiveStartMode != AttachToRemoteServer && inferiorPid();
1157
1158
}

1159
1160
void CdbEngine::interruptInferior()
{
1161
1162
    if (debug)
        qDebug() << "CdbEngine::interruptInferior()" << stateName(state());
1163
1164

    bool ok = false;
1165
    if (!canInterruptInferior())
1166
        showMessage(tr