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

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

#include "bytearrayinputstream.h"
34
#include "cdboptionspage.h"
hjk's avatar
hjk committed
35
#include "cdbparsehelpers.h"
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

#include <debugger/breakhandler.h>
#include <debugger/debuggeractions.h>
#include <debugger/debuggercore.h>
#include <debugger/debuggerprotocol.h>
#include <debugger/debuggermainwindow.h>
#include <debugger/debuggerstartparameters.h>
#include <debugger/debuggertooltipmanager.h>
#include <debugger/disassembleragent.h>
#include <debugger/disassemblerlines.h>
#include <debugger/memoryagent.h>
#include <debugger/moduleshandler.h>
#include <debugger/registerhandler.h>
#include <debugger/stackhandler.h>
#include <debugger/threadshandler.h>
#include <debugger/watchhandler.h>
#include <debugger/procinterrupt.h>
#include <debugger/sourceutils.h>
#include <debugger/shared/cdbsymbolpathlisteditor.h>
#include <debugger/shared/hostutils.h>
56
57

#include <coreplugin/icore.h>
58
#include <coreplugin/messagebox.h>
59
#include <projectexplorer/taskhub.h>
60
#include <texteditor/texteditor.h>
61

62
#include <utils/synchronousprocess.h>
63
#include <utils/qtcprocess.h>
64
65
66
#include <utils/winutils.h>
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
67
#include <utils/consoleprocess.h>
68
#include <utils/fileutils.h>
69
#include <utils/hostosinfo.h>
70
71

#include <cplusplus/findcdbbreakpoint.h>
72
#include <cpptools/cppmodelmanager.h>
73
#include <cpptools/cppworkingcopy.h>
74

75
#include <QDir>
76
77
78
79

#include <cctype>

enum { debug = 0 };
80
enum { debugLocals = 0 };
81
enum { debugSourceMapping = 0 };
82
enum { debugWatches = 0 };
83
84
enum { debugBreakpoints = 0 };

85
#define CB(callback) [this](const DebuggerResponse &r) { callback(r); }
86

87
#if 0
88
#  define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line);
89
#else
90
#  define STATE_DEBUG(state, func, line, notifyFunc)
91
92
#endif

93
94
95
96
97
98
99
100
/*!
    \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
101
    \li Notify the engine about the state of the debugging session:
102
        \list
103
104
105
106
        \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.
107
        \endlist
108
    \li Hook up with output/event callbacks and produce formatted output to be able
109
       to catch application output and exceptions.
110
    \li Provide some extension commands that produce output in a standardized (GDBMI)
111
112
      format that ends up in handleExtensionMessage(), for example:
      \list
113
114
115
116
      \li pid     Return debuggee pid for interrupting.
      \li locals  Print locals from SymbolGroup
      \li expandLocals Expand locals in symbol group
      \li registers, modules, threads
117
118
119
120
121
122
123
      \endlist
   \endlist

   Debugger commands can be posted by calling:

   \list

124
    \li postCommand(): Does not expect a response
125
    \li postBuiltinCommand(): Run a builtin-command producing free-format, multiline output
126
127
       that is captured by enclosing it in special tokens using the 'echo' command and
       then invokes a callback with a CdbBuiltinCommand structure.
128
    \li postExtensionCommand(): Run a command provided by the extension producing
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
       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).
*/
147

148
using namespace ProjectExplorer;
149
using namespace Utils;
150

151
namespace Debugger {
152
namespace Internal {
153

154
155
static const char localsPrefixC[] = "local.";

hjk's avatar
hjk committed
156
157
struct MemoryViewCookie
{
158
    explicit MemoryViewCookie(MemoryAgent *a = 0, QObject *e = 0,
159
                              quint64 addr = 0, quint64 l = 0) :
hjk's avatar
hjk committed
160
161
        agent(a), editorToken(e), address(addr), length(l)
    {}
162

163
    MemoryAgent *agent;
164
165
166
167
168
    QObject *editorToken;
    quint64 address;
    quint64 length;
};

169
170
171
172
173
174
175
176
177
struct MemoryChangeCookie
{
    explicit MemoryChangeCookie(quint64 addr = 0, const QByteArray &d = QByteArray()) :
                               address(addr), data(d) {}

    quint64 address;
    QByteArray data;
};

178
} // namespace Internal
179
180
} // namespace Debugger

181
Q_DECLARE_METATYPE(Debugger::Internal::MemoryViewCookie)
182
Q_DECLARE_METATYPE(Debugger::Internal::MemoryChangeCookie)
183
184

namespace Debugger {
185
namespace Internal {
186

187
static inline bool isCreatorConsole(const DebuggerRunParameters &sp)
hjk's avatar
hjk committed
188
{
hjk's avatar
hjk committed
189
    return !boolSetting(UseCdbConsole) && sp.useTerminal
190
           && (sp.startMode == StartInternal || sp.startMode == StartExternal);
hjk's avatar
hjk committed
191
}
192

193
// Base data structure for command queue entries with callback
194
class CdbCommand
195
{
196
public:
197
198
    CdbCommand() {}
    CdbCommand(CdbEngine::CommandHandler h) : handler(h) {}
199

200
    CdbEngine::CommandHandler handler;
201
202
203
204
};

static inline bool validMode(DebuggerStartMode sm)
{
205
    return sm != NoStartMode;
206
207
208
}

// Accessed by RunControlFactory
209
DebuggerEngine *createCdbEngine(const DebuggerRunParameters &rp, QStringList *errors)
210
{
211
    if (HostOsInfo::isWindowsHost()) {
212
213
        if (validMode(rp.startMode))
            return new CdbEngine(rp);
214
        errors->append(CdbEngine::tr("Internal error: Invalid start parameters passed for the CDB engine."));
215
    } else {
216
        errors->append(CdbEngine::tr("Unsupported CDB host system."));
217
    }
218
219
220
    return 0;
}

221
void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
222
{
223
    if (HostOsInfo::isWindowsHost()) {
224
        opts->push_back(new CdbOptionsPage);
225
226
        opts->push_back(new CdbPathsPage);
    }
227
228
229
230
}

#define QT_CREATOR_CDB_EXT "qtcreatorcdbext"

231
CdbEngine::CdbEngine(const DebuggerRunParameters &sp) :
232
    DebuggerEngine(sp),
233
    m_tokenPrefix("<token>"),
234
    m_effectiveStartMode(NoStartMode),
235
236
237
    m_accessible(false),
    m_specialStopMode(NoSpecialStop),
    m_nextCommandToken(0),
238
    m_currentBuiltinResponseToken(-1),
hjk's avatar
hjk committed
239
    m_extensionCommandPrefixBA("!" QT_CREATOR_CDB_EXT "."),
240
241
    m_operateByInstructionPending(true),
    m_operateByInstruction(true), // Default CDB setting
242
    m_verboseLogPending(true),
243
    m_verboseLog(false), // Default CDB setting
244
    m_hasDebuggee(false),
245
    m_wow64State(wow64Uninitialized),
246
    m_elapsedLogTime(0),
247
    m_sourceStepInto(false),
248
    m_watchPointX(0),
249
250
    m_watchPointY(0),
    m_ignoreCdbOutput(false)
251
252
{
    setObjectName(QLatin1String("CdbEngine"));
hjk's avatar
hjk committed
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267

    connect(action(OperateByInstruction), &QAction::triggered,
            this, &CdbEngine::operateByInstructionTriggered);
    connect(action(VerboseLog), &QAction::triggered,
            this, &CdbEngine::verboseLogTriggered);
    connect(action(CreateFullBacktrace), &QAction::triggered,
            this, &CdbEngine::createFullBacktrace);
    connect(&m_process, static_cast<void(QProcess::*)(int)>(&QProcess::finished),
            this, &CdbEngine::processFinished);
    connect(&m_process, static_cast<void(QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
            this, &CdbEngine::processError);
    connect(&m_process, &QProcess::readyReadStandardOutput,
            this, &CdbEngine::readyReadStandardOut);
    connect(&m_process, &QProcess::readyReadStandardError,
            this, &CdbEngine::readyReadStandardOut);
268
269
}

270
271
272
void CdbEngine::init()
{
    m_effectiveStartMode = NoStartMode;
273
    notifyInferiorPid(0);
274
275
276
    m_accessible = false;
    m_specialStopMode = NoSpecialStop;
    m_nextCommandToken  = 0;
277
    m_currentBuiltinResponseToken = -1;
hjk's avatar
hjk committed
278
279
    m_operateByInstructionPending = action(OperateByInstruction)->isChecked();
    m_verboseLogPending = boolSetting(VerboseLog);
280
    m_operateByInstruction = true; // Default CDB setting
281
    m_verboseLog = false; // Default CDB setting
282
283
284
285
    m_hasDebuggee = false;
    m_sourceStepInto = false;
    m_watchPointX = m_watchPointY = 0;
    m_ignoreCdbOutput = false;
286
    m_autoBreakPointCorrection = false;
287
    m_wow64State = wow64Uninitialized;
288
289

    m_outputBuffer.clear();
290
    m_commandForToken.clear();
291
    m_currentBuiltinResponse.clear();
292
293
    m_extensionMessageBuffer.clear();
    m_pendingBreakpointMap.clear();
294
295
    m_insertSubBreakpointMap.clear();
    m_pendingSubBreakpointMap.clear();
296
    m_customSpecialStopData.clear();
297
    m_symbolAddressCache.clear();
298
    m_coreStopReason.reset();
299
300
301

    // Create local list of mappings in native separators
    m_sourcePathMappings.clear();
302
    const QSharedPointer<GlobalDebuggerOptions> globalOptions = Internal::globalDebuggerOptions();
Orgad Shaneh's avatar
Orgad Shaneh committed
303
304
305
306
    SourcePathMap sourcePathMap = globalOptions->sourcePathMap;
    if (!sourcePathMap.isEmpty()) {
        m_sourcePathMappings.reserve(sourcePathMap.size());
        for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd(); it != cend; ++it) {
307
308
309
310
            m_sourcePathMappings.push_back(SourcePathMapping(QDir::toNativeSeparators(it.key()),
                                                             QDir::toNativeSeparators(it.value())));
        }
    }
311
312
    // update source path maps from debugger start params
    mergeStartParametersSourcePathMap();
313
    QTC_ASSERT(m_process.state() != QProcess::Running, SynchronousProcess::stopProcess(m_process));
314
315
}

316
317
318
319
320
321
CdbEngine::~CdbEngine()
{
}

void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
{
322
323
324
    // To be set next time session becomes accessible
    m_operateByInstructionPending = operateByInstruction;
    if (state() == InferiorStopOk)
325
326
327
        syncOperateByInstruction(operateByInstruction);
}

328
329
330
331
332
333
334
void CdbEngine::verboseLogTriggered(bool verboseLog)
{
    m_verboseLogPending = verboseLog;
    if (state() == InferiorStopOk)
        syncVerboseLog(verboseLog);
}

335
336
void CdbEngine::syncOperateByInstruction(bool operateByInstruction)
{
337
338
    if (debug)
        qDebug("syncOperateByInstruction current: %d new %d", m_operateByInstruction, operateByInstruction);
339
340
    if (m_operateByInstruction == operateByInstruction)
        return;
341
    QTC_ASSERT(m_accessible, return);
342
    m_operateByInstruction = operateByInstruction;
343
344
    postCommand(DebuggerCommand(m_operateByInstruction ? QByteArray("l-t") : QByteArray("l+t")));
    postCommand(DebuggerCommand(m_operateByInstruction ? QByteArray("l-s") : QByteArray("l+s")));
345
346
}

347
348
349
350
351
352
void CdbEngine::syncVerboseLog(bool verboseLog)
{
    if (m_verboseLog == verboseLog)
        return;
    QTC_ASSERT(m_accessible, return);
    m_verboseLog = verboseLog;
353
    postCommand(DebuggerCommand(m_verboseLog ? QByteArray("!sym noisy") : QByteArray("!sym quiet")));
354
355
}

356
bool CdbEngine::canHandleToolTip(const DebuggerToolTipContext &context) const
357
{
hjk's avatar
hjk committed
358
359
360
361
362
    Q_UNUSED(context);
    // Tooltips matching local variables are already handled in the
    // base class. We don't handle anything else here in CDB
    // as it can slow debugging down.
    return false;
363
364
365
}

// Determine full path to the CDB extension library.
366
QString CdbEngine::extensionLibraryName(bool is64Bit)
367
368
369
370
{
    // Determine extension lib name and path to use
    QString rc;
    QTextStream(&rc) << QFileInfo(QCoreApplication::applicationDirPath()).path()
hjk's avatar
hjk committed
371
                     << "/lib/" << (is64Bit ? QT_CREATOR_CDB_EXT "64" : QT_CREATOR_CDB_EXT "32")
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
                     << '/' << 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;
}

413
// Start the console stub with the sub process. Continue in consoleStubProcessStarted.
414
bool CdbEngine::startConsole(const DebuggerRunParameters &sp, QString *errorMessage)
415
416
417
{
    if (debug)
        qDebug("startConsole %s", qPrintable(sp.executable));
418
419
    m_consoleStub.reset(new ConsoleProcess);
    m_consoleStub->setMode(ConsoleProcess::Suspend);
420
421
422
423
424
425
    connect(m_consoleStub.data(), &ConsoleProcess::processError,
            this, &CdbEngine::consoleStubError);
    connect(m_consoleStub.data(), &ConsoleProcess::processStarted,
            this, &CdbEngine::consoleStubProcessStarted);
    connect(m_consoleStub.data(), &ConsoleProcess::stubStopped,
            this, &CdbEngine::consoleStubExited);
426
    m_consoleStub->setWorkingDirectory(sp.workingDirectory);
427
428
    if (sp.environment.size())
        m_consoleStub->setEnvironment(sp.environment);
429
    if (!m_consoleStub->start(sp.executable, sp.processArgs)) {
430
        *errorMessage = tr("The console process \"%1\" could not be started.").arg(sp.executable);
431
432
433
434
435
        return false;
    }
    return true;
}

436
void CdbEngine::consoleStubError(const QString &msg)
437
{
438
    if (debug)
439
440
441
442
        qDebug("consoleStubProcessMessage() in %s %s", stateName(state()), qPrintable(msg));
    if (state() == EngineSetupRequested) {
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
443
    } else {
444
445
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
        notifyEngineIll();
446
    }
447
    Core::AsynchronousMessageBox::critical(tr("Debugger Error"), msg);
448
449
450
451
452
453
454
}

void CdbEngine::consoleStubProcessStarted()
{
    if (debug)
        qDebug("consoleStubProcessStarted() PID=%lld", m_consoleStub->applicationPID());
    // Attach to console process.
455
    DebuggerRunParameters attachParameters = runParameters();
456
457
458
459
    attachParameters.executable.clear();
    attachParameters.processArgs.clear();
    attachParameters.attachPID = m_consoleStub->applicationPID();
    attachParameters.startMode = AttachExternal;
460
    attachParameters.useTerminal = false;
461
462
463
464
    showMessage(QString::fromLatin1("Attaching to %1...").arg(attachParameters.attachPID), LogMisc);
    QString errorMessage;
    if (!launchCDB(attachParameters, &errorMessage)) {
        showMessage(errorMessage, LogError);
465
        Core::AsynchronousMessageBox::critical(tr("Failed to Start the Debugger"), errorMessage);
466
467
468
469
470
471
472
473
474
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
    }
}

void CdbEngine::consoleStubExited()
{
}

475
476
void CdbEngine::createFullBacktrace()
{
477
    postCommand(DebuggerCommand("~*kp", BuiltinCommand, CB(handleCreateFullBackTrace)));
478
479
}

480
void CdbEngine::handleCreateFullBackTrace(const DebuggerResponse &response)
481
{
482
    Internal::openTextEditor(QLatin1String("Backtrace $"), response.data.toLatin1());
483
484
}

485
486
487
488
489
void CdbEngine::setupEngine()
{
    if (debug)
        qDebug(">setupEngine");

490
491
492
    init();
    if (!m_logTime.elapsed())
        m_logTime.start();
493
494
495
496
497
    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.
498
499
500
    const DebuggerRunParameters &rp = runParameters();
    const bool launchConsole = isCreatorConsole(rp);
    m_effectiveStartMode = launchConsole ? AttachExternal : rp.startMode;
501
    const bool ok = launchConsole ?
502
503
                startConsole(runParameters(), &errorMessage) :
                launchCDB(runParameters(), &errorMessage);
504
505
506
507
    if (debug)
        qDebug("<setupEngine ok=%d", ok);
    if (!ok) {
        showMessage(errorMessage, LogError);
508
        Core::AsynchronousMessageBox::critical(tr("Failed to Start the Debugger"), errorMessage);
509
510
511
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
    }
512
513
514
515
516

    DisplayFormats stringFormats;
    stringFormats.append(SimpleFormat);
    stringFormats.append(SeparateFormat);

517
518
519
520
521
    WatchHandler *wh = watchHandler();
    wh->addTypeFormats("QString", stringFormats);
    wh->addTypeFormats("QString *", stringFormats);
    wh->addTypeFormats("QByteArray", stringFormats);
    wh->addTypeFormats("QByteArray *", stringFormats);
522
    wh->addTypeFormats("std__basic_string", stringFormats);  // Python dumper naming convention for std::[w]string
523
524
525
526

    DisplayFormats imageFormats;
    imageFormats.append(SimpleFormat);
    imageFormats.append(EnhancedFormat);
527
528
    wh->addTypeFormats("QImage", imageFormats);
    wh->addTypeFormats("QImage *", imageFormats);
529
530
}

531
bool CdbEngine::launchCDB(const DebuggerRunParameters &sp, QString *errorMessage)
532
533
534
{
    if (debug)
        qDebug("launchCDB startMode=%d", sp.startMode);
535
    const QChar blank(QLatin1Char(' '));
536
    // Start engine which will run until initial breakpoint:
537
    // Determine binary (force MSVC), extension lib name and path to use
538
539
    // The extension is passed as relative name with the path variable set
    //(does not work with absolute path names)
hjk's avatar
hjk committed
540
    const QString executable = sp.debuggerCommand;
541
542
543
544
545
    if (executable.isEmpty()) {
        *errorMessage = tr("There is no CDB executable specified.");
        return false;
    }

hjk's avatar
hjk committed
546
547
    bool cdbIs64Bit = Utils::is64BitWindowsBinary(executable);
    if (!cdbIs64Bit)
548
        m_wow64State = noWow64Stack;
hjk's avatar
hjk committed
549
    const QFileInfo extensionFi(CdbEngine::extensionLibraryName(cdbIs64Bit));
550
    if (!extensionFi.isFile()) {
551
552
        *errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found.\n"
                                            "If you build Qt Creator from sources, check out "
Eike Ziller's avatar
Eike Ziller committed
553
                                            "https://code.qt.io/cgit/qt-creator/binary-artifacts.git/.").
554
555
556
                arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
        return false;
    }
557
    const QString extensionFileName = extensionFi.fileName();
558
559
    // Prepare arguments
    QStringList arguments;
560
    const bool isRemote = sp.startMode == AttachToRemoteServer;
561
562
563
564
565
    if (isRemote) { // Must be first
        arguments << QLatin1String("-remote") << sp.remoteChannel;
    } else {
        arguments << (QLatin1String("-a") + extensionFileName);
    }
566
567
568
569
    // Source line info/No terminal breakpoint / Pull extension
    arguments << QLatin1String("-lines") << QLatin1String("-G")
    // register idle (debuggee stop) notification
              << QLatin1String("-c")
570
              << QLatin1String(".idle_cmd ") + QString::fromLatin1(m_extensionCommandPrefixBA) + QLatin1String("idle");
571
572
    if (sp.useTerminal) // Separate console
        arguments << QLatin1String("-2");
hjk's avatar
hjk committed
573
    if (boolSetting(IgnoreFirstChanceAccessViolation))
574
        arguments << QLatin1String("-x");
575

hjk's avatar
hjk committed
576
    const QStringList &symbolPaths = stringListSetting(CdbSymbolPaths);
577
    if (!symbolPaths.isEmpty())
hjk's avatar
hjk committed
578
        arguments << QLatin1String("-y") << symbolPaths.join(QLatin1Char(';'));
hjk's avatar
hjk committed
579
    const QStringList &sourcePaths = stringListSetting(CdbSourcePaths);
580
    if (!sourcePaths.isEmpty())
hjk's avatar
hjk committed
581
        arguments << QLatin1String("-srcpath") << sourcePaths.join(QLatin1Char(';'));
582

583
    // Compile argument string preserving quotes
hjk's avatar
hjk committed
584
    QString nativeArguments = stringSetting(CdbAdditionalArguments);
585
586
587
    switch (sp.startMode) {
    case StartInternal:
    case StartExternal:
588
589
        if (!nativeArguments.isEmpty())
            nativeArguments.push_back(blank);
590
        QtcProcess::addArgs(&nativeArguments, QStringList(QDir::toNativeSeparators(sp.executable)));
591
        break;
592
    case AttachToRemoteServer:
593
        break;
594
    case AttachExternal:
595
    case AttachCrashedExternal:
596
        arguments << QLatin1String("-p") << QString::number(sp.attachPID);
597
        if (sp.startMode == AttachCrashedExternal) {
598
            arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g");
599
        } else {
600
            if (isCreatorConsole(runParameters()))
601
602
                arguments << QLatin1String("-pr") << QLatin1String("-pb");
        }
603
        break;
604
605
606
    case AttachCore:
        arguments << QLatin1String("-z") << sp.coreFile;
        break;
607
608
609
610
    default:
        *errorMessage = QString::fromLatin1("Internal error: Unsupported start mode %1.").arg(sp.startMode);
        return false;
    }
611
612
613
614
615
616
    if (!sp.processArgs.isEmpty()) { // Complete native argument string.
        if (!nativeArguments.isEmpty())
            nativeArguments.push_back(blank);
        nativeArguments += sp.processArgs;
    }

617
618
    const QString msg = QString::fromLatin1("Launching %1 %2\nusing %3 of %4.").
            arg(QDir::toNativeSeparators(executable),
hjk's avatar
hjk committed
619
                arguments.join(blank) + blank + nativeArguments,
620
621
622
623
624
                QDir::toNativeSeparators(extensionFi.absoluteFilePath()),
                extensionFi.lastModified().toString(Qt::SystemLocaleShortDate));
    showMessage(msg, LogMisc);

    m_outputBuffer.clear();
625
    m_autoBreakPointCorrection = false;
626
627
628
629
    const QStringList environment = sp.environment.size() == 0 ?
                                    QProcessEnvironment::systemEnvironment().toStringList() :
                                    sp.environment.toStringList();
    m_process.setEnvironment(mergeEnvironment(environment, extensionFi.absolutePath()));
630
631
    if (!sp.workingDirectory.isEmpty())
        m_process.setWorkingDirectory(sp.workingDirectory);
632

633
#ifdef Q_OS_WIN
634
635
    if (!nativeArguments.isEmpty()) // Appends
        m_process.setNativeArguments(nativeArguments);
636
#endif
637
638
639
640
641
642
    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;
    }
hjk's avatar
hjk committed
643
644

    const unsigned long pid = Utils::qPidToPid(m_process.pid());
645
646
647
    showMessage(QString::fromLatin1("%1 running as %2").
                arg(QDir::toNativeSeparators(executable)).arg(pid), LogMisc);
    m_hasDebuggee = true;
648
649
    if (isRemote) { // We do not get an 'idle' in a remote session, but are accessible
        m_accessible = true;
650
        postCommand(DebuggerCommand(".load " + extensionFileName.toLocal8Bit()));
651
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk")
652
653
        notifyEngineSetupOk();
    }
654
655
656
657
658
    return true;
}

void CdbEngine::setupInferior()
{
659
660
    if (debug)
        qDebug("setupInferior");
661
662
    const DebuggerRunParameters &rp = runParameters();
    if (!rp.commandsAfterConnect.isEmpty())
663
        postCommand(DebuggerCommand(rp.commandsAfterConnect));
664
665
666
    // QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
    // (attemptBreakpointSynchronization() will be directly called then)
    attemptBreakpointSynchronization();
667
    if (rp.breakOnMain) {
668
        const BreakpointParameters bp(BreakpointAtMain);
669
        BreakpointModelId id(quint16(-1));
670
671
672
673
674
675
676
677
678
        postCommand(DebuggerCommand(
                        cdbAddBreakpointCommand(bp, m_sourcePathMappings, id, true),
                        BuiltinCommand,
                        [this, id](const DebuggerResponse &r) { handleBreakInsert(r, id); }));
    }
    postCommand(DebuggerCommand("sxn 0x4000001f")); // Do not break on WowX86 exceptions.
    postCommand(DebuggerCommand("sxn ibp")); // Do not break on initial breakpoints.
    postCommand(DebuggerCommand(".asm source_line")); // Source line in assembly
    postCommand(DebuggerCommand(m_extensionCommandPrefixBA + "setparameter maxStringLength="
hjk's avatar
hjk committed
679
                + action(MaximalStringLength)->value().toByteArray()
680
                + " maxStackDepth="
681
682
                + action(MaximalStackDepth)->value().toByteArray()));
    postCommand(DebuggerCommand("pid", ExtensionCommand, CB(handlePid)));
683
684
}

685
686
687
688
689
690
691
692
693
694
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:
695
696
697
        return "MSVCR110";
    case Abi::WindowsMsvc2013Flavor:
        return "MSVCR120";
Joerg Bornemann's avatar
Joerg Bornemann committed
698
699
    case Abi::WindowsMsvc2015Flavor:
        return "MSVCR140";
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
    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;
}

718
719
void CdbEngine::runEngine()
{
720
721
    if (debug)
        qDebug("runEngine");
722

hjk's avatar
hjk committed
723
    const QStringList breakEvents = stringListSetting(CdbBreakEvents);
724
    foreach (const QString &breakEvent, breakEvents)
725
        postCommand(DebuggerCommand(QByteArray("sxe ") + breakEvent.toLatin1()));
726
727
    // Break functions: each function must be fully qualified,
    // else the debugger will slow down considerably.
hjk's avatar
hjk committed
728
    if (boolSetting(CdbBreakOnCrtDbgReport)) {
729
        const QByteArray module = msvcRunTime(runParameters().toolChainAbi.osFlavor());
730
        const QByteArray debugModule = module + 'D';
731
        const QByteArray wideFunc = QByteArray(CdbOptionsPage::crtDbgReport).append('W');
732
733
734
735
736
737
738
739
740
741
742
743
        postCommand(DebuggerCommand(
                                breakAtFunctionCommand(CdbOptionsPage::crtDbgReport, module), BuiltinCommand,
                                [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); }));
        postCommand(DebuggerCommand(
                                breakAtFunctionCommand(wideFunc, module), BuiltinCommand,
                                [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); }));
        postCommand(DebuggerCommand(
                                breakAtFunctionCommand(CdbOptionsPage::crtDbgReport, debugModule), BuiltinCommand,
                                [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); }));
        postCommand(DebuggerCommand(
                                breakAtFunctionCommand(wideFunc, debugModule), BuiltinCommand,
                                [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); }));
744
    }
hjk's avatar
hjk committed
745
    if (boolSetting(BreakOnWarning)) {
746
747
748
749
        postCommand(DebuggerCommand( "bm /( QtCored4!qWarning", BuiltinCommand, // 'bm': All overloads.
                                [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); }));
        postCommand(DebuggerCommand( "bm /( Qt5Cored!QMessageLogger::warning", BuiltinCommand,
                                [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); }));
750
    }
hjk's avatar
hjk committed
751
    if (boolSetting(BreakOnFatal)) {
752
753
754
755
        postCommand(DebuggerCommand("bm /( QtCored4!qFatal", BuiltinCommand, // 'bm': All overloads.
                           [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); }));
        postCommand(DebuggerCommand("bm /( Qt5Cored!QMessageLogger::fatal", BuiltinCommand,
                           [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); }));
756
    }
757
    if (runParameters().startMode == AttachCore) {
758
        QTC_ASSERT(!m_coreStopReason.isNull(), return; );
hjk's avatar
hjk committed
759
        notifyEngineRunOkAndInferiorUnrunnable();
760
761
        processStop(*m_coreStopReason, false);
    } else {
762
        doContinueInferior();
763
    }
764
765
}

766
767
bool CdbEngine::commandsPending() const
{
768
    return !m_commandForToken.isEmpty();
769
770
}

771
772
773
774
775
776
777
778
779
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");
780
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
781
782
783
        notifyInferiorShutdownOk();
        return;
    }
784

785
    if (m_accessible) { // except console.
786
        if (runParameters().startMode == AttachExternal || runParameters().startMode == AttachCrashedExternal)
787
            detachDebugger();
788
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
789
790
        notifyInferiorShutdownOk();
    } else {
791
792
793
794
795
796
797
798
799
800
801
802
803
        // 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;
        }
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
        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)
819
820
821
822
        qDebug("CdbEngine::shutdownEngine in state '%s', process running %d,"
               "accessible=%d,commands pending=%d",
               stateName(state()), isCdbProcessRunning(), m_accessible,
               commandsPending());
823
824

    if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
825
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
826
827
828
829
        notifyEngineShutdownOk();
        return;
    }

830
    // No longer trigger anything from messages
831
    m_ignoreCdbOutput = true;
832
833
    // Go for kill if there are commands pending.
    if (m_accessible && !commandsPending()) {
834
        // detach (except console): Wait for debugger to finish.
835
        if (runParameters().startMode == AttachExternal || runParameters().startMode == AttachCrashedExternal)
836
            detachDebugger();
837
        // Remote requires a bit more force to quit.
838
        if (m_effectiveStartMode == AttachToRemoteServer) {
839
840
            postCommand(DebuggerCommand(m_extensionCommandPrefixBA + "shutdownex"));
            postCommand(DebuggerCommand("qq"));
841
        } else {
842
            postCommand(DebuggerCommand("q"));
843
844
845
        }
    } else {
        // Remote process. No can do, currently
846
        SynchronousProcess::stopProcess(m_process);
847
848
849
    }
}

850
851
852
853
854
855
856
857
858
859
860
861
862
void CdbEngine::abortDebugger()
{
    if (targetState() == DebuggerFinished) {
        // We already tried. Try harder.
        showMessage(QLatin1String("ABORTING DEBUGGER. SECOND TIME."));
        m_process.kill();
    } else {
        // Be friendly the first time. This will change targetState().
        showMessage(QLatin1String("ABORTING DEBUGGER. FIRST TIME."));
        quitDebugger();
    }
}

863
864
865
void CdbEngine::processFinished()
{
    if (debug)
866
867
        qDebug("CdbEngine::processFinished %dms '%s' (exit state=%d, ex=%d)",
               elapsedLogTime(), stateName(state()), m_process.exitStatus(), m_process.exitCode());
868

869
870
871
    notifyDebuggerProcessFinished(m_process.exitCode(),
                                  m_process.exitStatus(),
                                  QLatin1String("CDB"));
872
873
874
875
}

void CdbEngine::detachDebugger()
{
876
    postCommand(DebuggerCommand(".detach"));
877
878
}

879
880
881
882
883
static inline bool isWatchIName(const QByteArray &iname)
{
    return iname.startsWith("watch");
}

hjk's avatar
hjk committed
884
bool CdbEngine::hasCapability(unsigned cap) const
885
{
hjk's avatar
hjk committed
886
887
    return cap & (DisassemblerCapability | RegisterCapability
           | ShowMemoryCapability
888
           |WatchpointByAddressCapability|JumpToLineCapability|AddWatcherCapability|WatchWidgetsCapability
889
           |ReloadModuleCapability
890
           |BreakOnThrowAndCatchCapability // Sort-of: Can break on throw().
891
           |BreakConditionCapability|TracePointCapability
892
           |BreakModuleCapability
893
           |CreateFullBacktraceCapability
894
           |OperateByInstructionCapability
895
           |RunToLineCapability
896
897
           |MemoryAddressCapability
           |AdditionalQmlStackCapability);
898
899
900
901
}

void CdbEngine::executeStep()
{
902
903
    if (!m_operateByInstruction)
        m_sourceStepInto = true; // See explanation at handleStackTrace().
904
    postCommand(DebuggerCommand(QByteArray("t"))); // Step into-> t (trace)
905
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
906
907
908
909
910
    notifyInferiorRunRequested();
}

void CdbEngine::executeStepOut()
{
911
    postCommand(DebuggerCommand(QByteArray("gu"))); // Step out-> gu (go up)
912
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__,