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

#include <cctype>

79
80
Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgent*)
Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgent*)
81
82

enum { debug = 0 };
83
enum { debugLocals = 0 };
84
enum { debugSourceMapping = 0 };
85
enum { debugWatches = 0 };
86
87
enum { debugBreakpoints = 0 };

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

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

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

   Debugger commands can be posted by calling:

   \list

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

151
using namespace ProjectExplorer;
152
using namespace Utils;
153

154
namespace Debugger {
155
namespace Internal {
156

157
158
static const char localsPrefixC[] = "local.";

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

166
    MemoryAgent *agent;
167
168
169
170
171
    QObject *editorToken;
    quint64 address;
    quint64 length;
};

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

    quint64 address;
    QByteArray data;
};

181
} // namespace Internal
182
183
} // namespace Debugger

184
Q_DECLARE_METATYPE(Debugger::Internal::MemoryViewCookie)
185
Q_DECLARE_METATYPE(Debugger::Internal::MemoryChangeCookie)
186
187

namespace Debugger {
188
namespace Internal {
189

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

196
// Base data structure for command queue entries with callback
197
class CdbCommand
198
{
199
public:
200
    CdbCommand()
201
        : token(0)
202
203
    {}

204
    CdbCommand(int token, CdbEngine::CommandHandler h)
205
        : token(token), handler(h)
206
    {}
207
208
209

    int token;

210
    CdbEngine::CommandHandler handler;
211
212
213
214
215
216
217
218
219
220
221
222
223
224
};

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)
{
225
    return sm != NoStartMode;
226
227
228
}

// Accessed by RunControlFactory
229
DebuggerEngine *createCdbEngine(const DebuggerRunParameters &rp, QStringList *errors)
230
{
231
    if (HostOsInfo::isWindowsHost()) {
232
233
        if (validMode(rp.startMode))
            return new CdbEngine(rp);
234
        errors->append(CdbEngine::tr("Internal error: Invalid start parameters passed for the CDB engine."));
235
    } else {
236
        errors->append(CdbEngine::tr("Unsupported CDB host system."));
237
    }
238
239
240
    return 0;
}

241
void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
242
{
243
    if (HostOsInfo::isWindowsHost()) {
244
        opts->push_back(new CdbOptionsPage);
245
246
        opts->push_back(new CdbPathsPage);
    }
247
248
249
250
}

#define QT_CREATOR_CDB_EXT "qtcreatorcdbext"

251
CdbEngine::CdbEngine(const DebuggerRunParameters &sp) :
252
    DebuggerEngine(sp),
253
    m_tokenPrefix("<token>"),
254
    m_effectiveStartMode(NoStartMode),
255
256
257
    m_accessible(false),
    m_specialStopMode(NoSpecialStop),
    m_nextCommandToken(0),
258
    m_currentBuiltinResponseToken(-1),
hjk's avatar
hjk committed
259
    m_extensionCommandPrefixBA("!" QT_CREATOR_CDB_EXT "."),
260
261
    m_operateByInstructionPending(true),
    m_operateByInstruction(true), // Default CDB setting
262
    m_verboseLogPending(true),
263
    m_verboseLog(false), // Default CDB setting
264
    m_hasDebuggee(false),
265
    m_wow64State(wow64Uninitialized),
266
    m_elapsedLogTime(0),
267
    m_sourceStepInto(false),
268
    m_watchPointX(0),
269
270
    m_watchPointY(0),
    m_ignoreCdbOutput(false)
271
272
{
    setObjectName(QLatin1String("CdbEngine"));
hjk's avatar
hjk committed
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287

    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);
288
289
}

290
291
292
void CdbEngine::init()
{
    m_effectiveStartMode = NoStartMode;
293
    notifyInferiorPid(0);
294
295
296
    m_accessible = false;
    m_specialStopMode = NoSpecialStop;
    m_nextCommandToken  = 0;
297
    m_currentBuiltinResponseToken = -1;
hjk's avatar
hjk committed
298
299
    m_operateByInstructionPending = action(OperateByInstruction)->isChecked();
    m_verboseLogPending = boolSetting(VerboseLog);
300
    m_operateByInstruction = true; // Default CDB setting
301
    m_verboseLog = false; // Default CDB setting
302
303
304
305
    m_hasDebuggee = false;
    m_sourceStepInto = false;
    m_watchPointX = m_watchPointY = 0;
    m_ignoreCdbOutput = false;
306
    m_autoBreakPointCorrection = false;
307
    m_wow64State = wow64Uninitialized;
308
309
310

    m_outputBuffer.clear();
    m_builtinCommandQueue.clear();
311
    m_currentBuiltinResponse.clear();
312
313
314
    m_extensionCommandQueue.clear();
    m_extensionMessageBuffer.clear();
    m_pendingBreakpointMap.clear();
315
316
    m_insertSubBreakpointMap.clear();
    m_pendingSubBreakpointMap.clear();
317
    m_customSpecialStopData.clear();
318
    m_symbolAddressCache.clear();
319
    m_coreStopReason.reset();
320
321
322

    // Create local list of mappings in native separators
    m_sourcePathMappings.clear();
323
    const QSharedPointer<GlobalDebuggerOptions> globalOptions = Internal::globalDebuggerOptions();
Orgad Shaneh's avatar
Orgad Shaneh committed
324
325
326
327
    SourcePathMap sourcePathMap = globalOptions->sourcePathMap;
    if (!sourcePathMap.isEmpty()) {
        m_sourcePathMappings.reserve(sourcePathMap.size());
        for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd(); it != cend; ++it) {
328
329
330
331
            m_sourcePathMappings.push_back(SourcePathMapping(QDir::toNativeSeparators(it.key()),
                                                             QDir::toNativeSeparators(it.value())));
        }
    }
332
333
    // update source path maps from debugger start params
    mergeStartParametersSourcePathMap();
334
    QTC_ASSERT(m_process.state() != QProcess::Running, SynchronousProcess::stopProcess(m_process));
335
336
}

337
338
339
340
341
342
CdbEngine::~CdbEngine()
{
}

void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
{
343
344
345
    // To be set next time session becomes accessible
    m_operateByInstructionPending = operateByInstruction;
    if (state() == InferiorStopOk)
346
347
348
        syncOperateByInstruction(operateByInstruction);
}

349
350
351
352
353
354
355
void CdbEngine::verboseLogTriggered(bool verboseLog)
{
    m_verboseLogPending = verboseLog;
    if (state() == InferiorStopOk)
        syncVerboseLog(verboseLog);
}

356
357
void CdbEngine::syncOperateByInstruction(bool operateByInstruction)
{
358
359
    if (debug)
        qDebug("syncOperateByInstruction current: %d new %d", m_operateByInstruction, operateByInstruction);
360
361
    if (m_operateByInstruction == operateByInstruction)
        return;
362
    QTC_ASSERT(m_accessible, return);
363
    m_operateByInstruction = operateByInstruction;
364
365
    postCommand(m_operateByInstruction ? QByteArray("l-t") : QByteArray("l+t"));
    postCommand(m_operateByInstruction ? QByteArray("l-s") : QByteArray("l+s"));
366
367
}

368
369
370
371
372
373
void CdbEngine::syncVerboseLog(bool verboseLog)
{
    if (m_verboseLog == verboseLog)
        return;
    QTC_ASSERT(m_accessible, return);
    m_verboseLog = verboseLog;
374
    postCommand(m_verboseLog ? QByteArray("!sym noisy") : QByteArray("!sym quiet"));
375
376
}

377
bool CdbEngine::canHandleToolTip(const DebuggerToolTipContext &context) const
378
{
hjk's avatar
hjk committed
379
380
381
382
383
    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;
384
385
386
}

// Determine full path to the CDB extension library.
387
QString CdbEngine::extensionLibraryName(bool is64Bit)
388
389
390
391
{
    // Determine extension lib name and path to use
    QString rc;
    QTextStream(&rc) << QFileInfo(QCoreApplication::applicationDirPath()).path()
hjk's avatar
hjk committed
392
                     << "/lib/" << (is64Bit ? QT_CREATOR_CDB_EXT "64" : QT_CREATOR_CDB_EXT "32")
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
                     << '/' << 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;
}

434
// Start the console stub with the sub process. Continue in consoleStubProcessStarted.
435
bool CdbEngine::startConsole(const DebuggerRunParameters &sp, QString *errorMessage)
436
437
438
{
    if (debug)
        qDebug("startConsole %s", qPrintable(sp.executable));
439
440
    m_consoleStub.reset(new ConsoleProcess);
    m_consoleStub->setMode(ConsoleProcess::Suspend);
441
442
443
444
445
446
    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);
447
    m_consoleStub->setWorkingDirectory(sp.workingDirectory);
448
449
    if (sp.environment.size())
        m_consoleStub->setEnvironment(sp.environment);
450
    if (!m_consoleStub->start(sp.executable, sp.processArgs)) {
451
        *errorMessage = tr("The console process \"%1\" could not be started.").arg(sp.executable);
452
453
454
455
456
        return false;
    }
    return true;
}

457
void CdbEngine::consoleStubError(const QString &msg)
458
{
459
    if (debug)
460
461
462
463
        qDebug("consoleStubProcessMessage() in %s %s", stateName(state()), qPrintable(msg));
    if (state() == EngineSetupRequested) {
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
464
    } else {
465
466
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
        notifyEngineIll();
467
    }
468
    Core::AsynchronousMessageBox::critical(tr("Debugger Error"), msg);
469
470
471
472
473
474
475
}

void CdbEngine::consoleStubProcessStarted()
{
    if (debug)
        qDebug("consoleStubProcessStarted() PID=%lld", m_consoleStub->applicationPID());
    // Attach to console process.
476
    DebuggerRunParameters attachParameters = runParameters();
477
478
479
480
    attachParameters.executable.clear();
    attachParameters.processArgs.clear();
    attachParameters.attachPID = m_consoleStub->applicationPID();
    attachParameters.startMode = AttachExternal;
481
    attachParameters.useTerminal = false;
482
483
484
485
    showMessage(QString::fromLatin1("Attaching to %1...").arg(attachParameters.attachPID), LogMisc);
    QString errorMessage;
    if (!launchCDB(attachParameters, &errorMessage)) {
        showMessage(errorMessage, LogError);
486
        Core::AsynchronousMessageBox::critical(tr("Failed to Start the Debugger"), errorMessage);
487
488
489
490
491
492
493
494
495
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
    }
}

void CdbEngine::consoleStubExited()
{
}

496
497
void CdbEngine::createFullBacktrace()
{
498
    postBuiltinCommand("~*kp", CB(handleCreateFullBackTrace));
499
500
}

501
void CdbEngine::handleCreateFullBackTrace(const DebuggerResponse &response)
502
{
503
    Internal::openTextEditor(QLatin1String("Backtrace $"), response.data.toLatin1());
504
505
}

506
507
508
509
510
void CdbEngine::setupEngine()
{
    if (debug)
        qDebug(">setupEngine");

511
512
513
    init();
    if (!m_logTime.elapsed())
        m_logTime.start();
514
515
516
517
518
    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.
519
520
521
    const DebuggerRunParameters &rp = runParameters();
    const bool launchConsole = isCreatorConsole(rp);
    m_effectiveStartMode = launchConsole ? AttachExternal : rp.startMode;
522
    const bool ok = launchConsole ?
523
524
                startConsole(runParameters(), &errorMessage) :
                launchCDB(runParameters(), &errorMessage);
525
526
527
528
    if (debug)
        qDebug("<setupEngine ok=%d", ok);
    if (!ok) {
        showMessage(errorMessage, LogError);
529
        Core::AsynchronousMessageBox::critical(tr("Failed to Start the Debugger"), errorMessage);
530
531
532
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
    }
533
534
535
536
537

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

538
539
540
541
542
    WatchHandler *wh = watchHandler();
    wh->addTypeFormats("QString", stringFormats);
    wh->addTypeFormats("QString *", stringFormats);
    wh->addTypeFormats("QByteArray", stringFormats);
    wh->addTypeFormats("QByteArray *", stringFormats);
543
    wh->addTypeFormats("std__basic_string", stringFormats);  // Python dumper naming convention for std::[w]string
544
545
546
547

    DisplayFormats imageFormats;
    imageFormats.append(SimpleFormat);
    imageFormats.append(EnhancedFormat);
548
549
    wh->addTypeFormats("QImage", imageFormats);
    wh->addTypeFormats("QImage *", imageFormats);
550
551
}

552
bool CdbEngine::launchCDB(const DebuggerRunParameters &sp, QString *errorMessage)
553
554
555
{
    if (debug)
        qDebug("launchCDB startMode=%d", sp.startMode);
556
    const QChar blank(QLatin1Char(' '));
557
    // Start engine which will run until initial breakpoint:
558
    // Determine binary (force MSVC), extension lib name and path to use
559
560
    // The extension is passed as relative name with the path variable set
    //(does not work with absolute path names)
hjk's avatar
hjk committed
561
    const QString executable = sp.debuggerCommand;
562
563
564
565
566
    if (executable.isEmpty()) {
        *errorMessage = tr("There is no CDB executable specified.");
        return false;
    }

hjk's avatar
hjk committed
567
568
    bool cdbIs64Bit = Utils::is64BitWindowsBinary(executable);
    if (!cdbIs64Bit)
569
        m_wow64State = noWow64Stack;
hjk's avatar
hjk committed
570
    const QFileInfo extensionFi(CdbEngine::extensionLibraryName(cdbIs64Bit));
571
    if (!extensionFi.isFile()) {
572
573
        *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
574
                                            "https://code.qt.io/cgit/qt-creator/binary-artifacts.git/.").
575
576
577
                arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
        return false;
    }
578
    const QString extensionFileName = extensionFi.fileName();
579
580
    // Prepare arguments
    QStringList arguments;
581
    const bool isRemote = sp.startMode == AttachToRemoteServer;
582
583
584
585
586
    if (isRemote) { // Must be first
        arguments << QLatin1String("-remote") << sp.remoteChannel;
    } else {
        arguments << (QLatin1String("-a") + extensionFileName);
    }
587
588
589
590
    // Source line info/No terminal breakpoint / Pull extension
    arguments << QLatin1String("-lines") << QLatin1String("-G")
    // register idle (debuggee stop) notification
              << QLatin1String("-c")
591
              << QLatin1String(".idle_cmd ") + QString::fromLatin1(m_extensionCommandPrefixBA) + QLatin1String("idle");
592
593
    if (sp.useTerminal) // Separate console
        arguments << QLatin1String("-2");
hjk's avatar
hjk committed
594
    if (boolSetting(IgnoreFirstChanceAccessViolation))
595
        arguments << QLatin1String("-x");
596

hjk's avatar
hjk committed
597
    const QStringList &symbolPaths = stringListSetting(CdbSymbolPaths);
598
    if (!symbolPaths.isEmpty())
hjk's avatar
hjk committed
599
        arguments << QLatin1String("-y") << symbolPaths.join(QLatin1Char(';'));
hjk's avatar
hjk committed
600
    const QStringList &sourcePaths = stringListSetting(CdbSourcePaths);
601
    if (!sourcePaths.isEmpty())
hjk's avatar
hjk committed
602
        arguments << QLatin1String("-srcpath") << sourcePaths.join(QLatin1Char(';'));
603

604
    // Compile argument string preserving quotes
hjk's avatar
hjk committed
605
    QString nativeArguments = stringSetting(CdbAdditionalArguments);
606
607
608
    switch (sp.startMode) {
    case StartInternal:
    case StartExternal:
609
610
        if (!nativeArguments.isEmpty())
            nativeArguments.push_back(blank);
611
        QtcProcess::addArgs(&nativeArguments, QStringList(QDir::toNativeSeparators(sp.executable)));
612
        break;
613
    case AttachToRemoteServer:
614
        break;
615
    case AttachExternal:
616
    case AttachCrashedExternal:
617
        arguments << QLatin1String("-p") << QString::number(sp.attachPID);
618
        if (sp.startMode == AttachCrashedExternal) {
619
            arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g");
620
        } else {
621
            if (isCreatorConsole(runParameters()))
622
623
                arguments << QLatin1String("-pr") << QLatin1String("-pb");
        }
624
        break;
625
626
627
    case AttachCore:
        arguments << QLatin1String("-z") << sp.coreFile;
        break;
628
629
630
631
    default:
        *errorMessage = QString::fromLatin1("Internal error: Unsupported start mode %1.").arg(sp.startMode);
        return false;
    }
632
633
634
635
636
637
    if (!sp.processArgs.isEmpty()) { // Complete native argument string.
        if (!nativeArguments.isEmpty())
            nativeArguments.push_back(blank);
        nativeArguments += sp.processArgs;
    }

638
639
    const QString msg = QString::fromLatin1("Launching %1 %2\nusing %3 of %4.").
            arg(QDir::toNativeSeparators(executable),
hjk's avatar
hjk committed
640
                arguments.join(blank) + blank + nativeArguments,
641
642
643
644
645
                QDir::toNativeSeparators(extensionFi.absoluteFilePath()),
                extensionFi.lastModified().toString(Qt::SystemLocaleShortDate));
    showMessage(msg, LogMisc);

    m_outputBuffer.clear();
646
    m_autoBreakPointCorrection = false;
647
648
649
650
    const QStringList environment = sp.environment.size() == 0 ?
                                    QProcessEnvironment::systemEnvironment().toStringList() :
                                    sp.environment.toStringList();
    m_process.setEnvironment(mergeEnvironment(environment, extensionFi.absolutePath()));
651
652
    if (!sp.workingDirectory.isEmpty())
        m_process.setWorkingDirectory(sp.workingDirectory);
653

654
#ifdef Q_OS_WIN
655
656
    if (!nativeArguments.isEmpty()) // Appends
        m_process.setNativeArguments(nativeArguments);
657
#endif
658
659
660
661
662
663
    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
664
665

    const unsigned long pid = Utils::qPidToPid(m_process.pid());
666
667
668
    showMessage(QString::fromLatin1("%1 running as %2").
                arg(QDir::toNativeSeparators(executable)).arg(pid), LogMisc);
    m_hasDebuggee = true;
669
670
671
672
    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();
673
        postCommand(loadCommand);
674
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk")
675
676
        notifyEngineSetupOk();
    }
677
678
679
680
681
    return true;
}

void CdbEngine::setupInferior()
{
682
683
    if (debug)
        qDebug("setupInferior");
684
685
    const DebuggerRunParameters &rp = runParameters();
    if (!rp.commandsAfterConnect.isEmpty())
686
        postCommand(rp.commandsAfterConnect);
687
688
689
    // QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
    // (attemptBreakpointSynchronization() will be directly called then)
    attemptBreakpointSynchronization();
690
    if (rp.breakOnMain) {
691
        const BreakpointParameters bp(BreakpointAtMain);
692
693
        BreakpointModelId id(quint16(-1));
        postBuiltinCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, id, true),
694
                           [this, id](const DebuggerResponse &r) { handleBreakInsert(r, id); });
695
    }
696
697
698
    postCommand("sxn 0x4000001f"); // Do not break on WowX86 exceptions.
    postCommand("sxn ibp"); // Do not break on initial breakpoints.
    postCommand(".asm source_line"); // Source line in assembly
699
    postCommand(m_extensionCommandPrefixBA + "setparameter maxStringLength="
hjk's avatar
hjk committed
700
                + action(MaximalStringLength)->value().toByteArray()
701
                + " maxStackDepth="
702
703
                + action(MaximalStackDepth)->value().toByteArray());
    postExtensionCommand("pid", QByteArray(), CB(handlePid));
704
705
}

706
707
708
709
710
711
712
713
714
715
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:
716
717
718
        return "MSVCR110";
    case Abi::WindowsMsvc2013Flavor:
        return "MSVCR120";
Joerg Bornemann's avatar
Joerg Bornemann committed
719
720
    case Abi::WindowsMsvc2015Flavor:
        return "MSVCR140";
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
    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;
}

739
740
void CdbEngine::runEngine()
{
741
742
    if (debug)
        qDebug("runEngine");
743

hjk's avatar
hjk committed
744
    const QStringList breakEvents = stringListSetting(CdbBreakEvents);
745
    foreach (const QString &breakEvent, breakEvents)
746
        postCommand(QByteArray("sxe ") + breakEvent.toLatin1());
747
748
    // Break functions: each function must be fully qualified,
    // else the debugger will slow down considerably.
hjk's avatar
hjk committed
749
    if (boolSetting(CdbBreakOnCrtDbgReport)) {
750
        const QByteArray module = msvcRunTime(runParameters().toolChainAbi.osFlavor());
751
        const QByteArray debugModule = module + 'D';
752
        const QByteArray wideFunc = QByteArray(CdbOptionsPage::crtDbgReport).append('W');
753
        postBuiltinCommand(breakAtFunctionCommand(CdbOptionsPage::crtDbgReport, module),
754
                           [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
755
        postBuiltinCommand(breakAtFunctionCommand(wideFunc, module),
756
                           [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
757
        postBuiltinCommand(breakAtFunctionCommand(CdbOptionsPage::crtDbgReport, debugModule),
758
                           [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
759
        postBuiltinCommand(breakAtFunctionCommand(wideFunc, debugModule),
760
                           [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
761
    }
hjk's avatar
hjk committed
762
    if (boolSetting(BreakOnWarning)) {
763
        postBuiltinCommand("bm /( QtCored4!qWarning", // 'bm': All overloads.
764
                           [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
765
        postBuiltinCommand("bm /( Qt5Cored!QMessageLogger::warning",
766
                           [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
767
    }
hjk's avatar
hjk committed
768
    if (boolSetting(BreakOnFatal)) {
769
        postBuiltinCommand("bm /( QtCored4!qFatal", // 'bm': All overloads.
770
                           [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
771
        postBuiltinCommand("bm /( Qt5Cored!QMessageLogger::fatal",
772
                           [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
773
    }
774
    if (runParameters().startMode == AttachCore) {
775
        QTC_ASSERT(!m_coreStopReason.isNull(), return; );
hjk's avatar
hjk committed
776
        notifyEngineRunOkAndInferiorUnrunnable();
777
778
        processStop(*m_coreStopReason, false);
    } else {
779
        doContinueInferior();
780
    }
781
782
}

783
784
785
786
787
bool CdbEngine::commandsPending() const
{
    return !m_builtinCommandQueue.isEmpty() || !m_extensionCommandQueue.isEmpty();
}

788
789
790
791
792
793
794
795
796
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");
797
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
798
799
800
        notifyInferiorShutdownOk();
        return;
    }
801

802
    if (m_accessible) { // except console.
803
        if (runParameters().startMode == AttachExternal || runParameters().startMode == AttachCrashedExternal)
804
            detachDebugger();
805
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
806
807
        notifyInferiorShutdownOk();
    } else {
808
809
810
811
812
813
814
815
816
817
818
819
820
        // 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;
        }
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
        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)
836
837
838
839
        qDebug("CdbEngine::shutdownEngine in state '%s', process running %d,"
               "accessible=%d,commands pending=%d",
               stateName(state()), isCdbProcessRunning(), m_accessible,
               commandsPending());
840
841

    if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
842
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
843
844
845
846
        notifyEngineShutdownOk();
        return;
    }

847
    // No longer trigger anything from messages
848
    m_ignoreCdbOutput = true;
849
850
    // Go for kill if there are commands pending.
    if (m_accessible && !commandsPending()) {
851
        // detach (except console): Wait for debugger to finish.
852
        if (runParameters().startMode == AttachExternal || runParameters().startMode == AttachCrashedExternal)
853
            detachDebugger();
854
        // Remote requires a bit more force to quit.
855
        if (m_effectiveStartMode == AttachToRemoteServer) {
856
857
            postCommand(m_extensionCommandPrefixBA + "shutdownex");
            postCommand("qq");
858
        } else {
859
            postCommand("q");
860
861
862
        }
    } else {
        // Remote process. No can do, currently
863
        SynchronousProcess::stopProcess(m_process);
864
865
866
    }
}

867
868
869
870
871
872
873
874
875
876
877
878
879
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();
    }
}

880
881
882
void CdbEngine::processFinished()
{
    if (debug)
883
884
        qDebug("CdbEngine::processFinished %dms '%s' (exit state=%d, ex=%d)",
               elapsedLogTime(), stateName(state()), m_process.exitStatus(), m_process.exitCode());
885

886
887
888
    notifyDebuggerProcessFinished(m_process.exitCode(),
                                  m_process.exitStatus(),
                                  QLatin1String("CDB"));
889
890
891
892
}

void CdbEngine::detachDebugger()
{
893
    postCommand(".detach");
894
895
}

896
897
898
899
900
static inline bool isWatchIName(const QByteArray &iname)
{
    return iname.startsWith("watch");
}

hjk's avatar
hjk committed
901
bool CdbEngine::hasCapability(unsigned cap) const
902
{
hjk's avatar
hjk committed
903
904
    return cap & (DisassemblerCapability | RegisterCapability
           | ShowMemoryCapability
905
           |WatchpointByAddressCapability|JumpToLineCapability|AddWatcherCapability|WatchWidgetsCapability
906
           |ReloadModuleCapability
907
           |BreakOnThrowAndCatchCapability // Sort-of: Can break on throw().
908
           |BreakConditionCapability|TracePointCapability
909
           |BreakModuleCapability
910
           |CreateFullBacktraceCapability
911
           |OperateByInstructionCapability
912
           |RunToLineCapability
913
914
           |MemoryAddressCapability
           |AdditionalQmlStackCapability);
915
916
917
918
}

void CdbEngine::executeStep()
{
919
920
    if (!m_operateByInstruction)
        m_sourceStepInto = true; // See explanation at handleStackTrace().
921
    postCommand(QByteArray("t")); // Step into-> t (trace)
922
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
923
924
925
926
927
    notifyInferiorRunRequested();
}

void CdbEngine::executeStepOut()
{
928
    postCommand(QByteArray("gu")); // Step out-> gu (go up)
929
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
930
931
932
933
934
    notifyInferiorRunRequested();
}

void CdbEngine::executeNext()
{
935
    postCommand(QByteArray("p")); // Step over -> p
936
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
    notifyInferiorRunRequested();
}

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

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

void CdbEngine::continueInferior()
{
952
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
953
954
955
956
957
958
    notifyInferiorRunRequested();
    doContinueInferior();
}

void CdbEngine::doContinueInferior()
{
959
    postCommand(QByteArray("g"));
960
961
}

962
963
bool CdbEngine::canInterruptInferior() const
{
964
    return m_effectiveStartMode != AttachToRemoteServer && inferiorPid();
965
966
}

967
968
void CdbEngine::interruptInferior()
{
969
970
    if (debug)
        qDebug() << "CdbEngine::interruptInferior()" << stateName(state());
971