cdbengine.cpp 122 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 CdbResponse &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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
class CdbResponse
{
public:
    CdbResponse()
        : commandSequence(0), success(false)
    {}

    QByteArray joinedReply() const;

    QByteArray command;

    // Continue with other commands as specified in CommandSequenceFlags
    unsigned commandSequence;

    QList<QByteArray> builtinReply;
    QByteArray extensionReply;
    QByteArray errorMessage;
    bool success;
};

216
// Base data structure for command queue entries with callback
217
class CdbCommand
218
{
219
public:
220
    CdbCommand()
221
        : token(0)
222
223
    {}

224
225
    CdbCommand(const QByteArray &cmd, int token, CdbEngine::CommandHandler h, unsigned nc)
        : token(token), handler(h)
226
227
228
229
    {
        response.command = cmd;
        response.commandSequence = nc;
    }
230
231
232

    int token;

233
    CdbEngine::CommandHandler handler;
234

235
    CdbResponse response; // FIXME: remove.
236
237
};

238
QByteArray CdbResponse::joinedReply() const
239
{
240
    if (builtinReply.isEmpty())
241
242
        return QByteArray();
    QByteArray answer;
243
244
    answer.reserve(120  * builtinReply.size());
    foreach (const QByteArray &l, builtinReply) {
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
        answer += l;
        answer += '\n';
    }
    return answer;
}

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)
{
263
    return sm != NoStartMode;
264
265
266
}

// Accessed by RunControlFactory
267
DebuggerEngine *createCdbEngine(const DebuggerRunParameters &rp, QStringList *errors)
268
{
269
    if (HostOsInfo::isWindowsHost()) {
270
271
        if (validMode(rp.startMode))
            return new CdbEngine(rp);
272
        errors->append(CdbEngine::tr("Internal error: Invalid start parameters passed for the CDB engine."));
273
    } else {
274
        errors->append(CdbEngine::tr("Unsupported CDB host system."));
275
    }
276
277
278
    return 0;
}

279
void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
280
{
281
    if (HostOsInfo::isWindowsHost()) {
282
        opts->push_back(new CdbOptionsPage);
283
284
        opts->push_back(new CdbPathsPage);
    }
285
286
287
288
}

#define QT_CREATOR_CDB_EXT "qtcreatorcdbext"

289
CdbEngine::CdbEngine(const DebuggerRunParameters &sp) :
290
    DebuggerEngine(sp),
291
    m_tokenPrefix("<token>"),
292
    m_effectiveStartMode(NoStartMode),
293
294
295
296
    m_accessible(false),
    m_specialStopMode(NoSpecialStop),
    m_nextCommandToken(0),
    m_currentBuiltinCommandIndex(-1),
hjk's avatar
hjk committed
297
    m_extensionCommandPrefixBA("!" QT_CREATOR_CDB_EXT "."),
298
299
    m_operateByInstructionPending(true),
    m_operateByInstruction(true), // Default CDB setting
300
    m_verboseLogPending(true),
301
    m_verboseLog(false), // Default CDB setting
302
    m_hasDebuggee(false),
303
    m_wow64State(wow64Uninitialized),
304
    m_elapsedLogTime(0),
305
    m_sourceStepInto(false),
306
    m_watchPointX(0),
307
308
    m_watchPointY(0),
    m_ignoreCdbOutput(false)
309
310
{
    setObjectName(QLatin1String("CdbEngine"));
hjk's avatar
hjk committed
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325

    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);
326
327
}

328
329
330
void CdbEngine::init()
{
    m_effectiveStartMode = NoStartMode;
331
    notifyInferiorPid(0);
332
333
334
335
    m_accessible = false;
    m_specialStopMode = NoSpecialStop;
    m_nextCommandToken  = 0;
    m_currentBuiltinCommandIndex = -1;
hjk's avatar
hjk committed
336
337
    m_operateByInstructionPending = action(OperateByInstruction)->isChecked();
    m_verboseLogPending = boolSetting(VerboseLog);
338
    m_operateByInstruction = true; // Default CDB setting
339
    m_verboseLog = false; // Default CDB setting
340
341
342
343
    m_hasDebuggee = false;
    m_sourceStepInto = false;
    m_watchPointX = m_watchPointY = 0;
    m_ignoreCdbOutput = false;
344
    m_autoBreakPointCorrection = false;
345
    m_wow64State = wow64Uninitialized;
346
347
348
349
350
351

    m_outputBuffer.clear();
    m_builtinCommandQueue.clear();
    m_extensionCommandQueue.clear();
    m_extensionMessageBuffer.clear();
    m_pendingBreakpointMap.clear();
352
353
    m_insertSubBreakpointMap.clear();
    m_pendingSubBreakpointMap.clear();
354
    m_customSpecialStopData.clear();
355
    m_symbolAddressCache.clear();
356
    m_coreStopReason.reset();
357
358
359

    // Create local list of mappings in native separators
    m_sourcePathMappings.clear();
360
    const QSharedPointer<GlobalDebuggerOptions> globalOptions = Internal::globalDebuggerOptions();
Orgad Shaneh's avatar
Orgad Shaneh committed
361
362
363
364
    SourcePathMap sourcePathMap = globalOptions->sourcePathMap;
    if (!sourcePathMap.isEmpty()) {
        m_sourcePathMappings.reserve(sourcePathMap.size());
        for (auto it = sourcePathMap.constBegin(), cend = sourcePathMap.constEnd(); it != cend; ++it) {
365
366
367
368
            m_sourcePathMappings.push_back(SourcePathMapping(QDir::toNativeSeparators(it.key()),
                                                             QDir::toNativeSeparators(it.value())));
        }
    }
369
370
    // update source path maps from debugger start params
    mergeStartParametersSourcePathMap();
371
    QTC_ASSERT(m_process.state() != QProcess::Running, SynchronousProcess::stopProcess(m_process));
372
373
}

374
375
376
377
378
379
CdbEngine::~CdbEngine()
{
}

void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
{
380
381
382
    // To be set next time session becomes accessible
    m_operateByInstructionPending = operateByInstruction;
    if (state() == InferiorStopOk)
383
384
385
        syncOperateByInstruction(operateByInstruction);
}

386
387
388
389
390
391
392
void CdbEngine::verboseLogTriggered(bool verboseLog)
{
    m_verboseLogPending = verboseLog;
    if (state() == InferiorStopOk)
        syncVerboseLog(verboseLog);
}

393
394
void CdbEngine::syncOperateByInstruction(bool operateByInstruction)
{
395
396
    if (debug)
        qDebug("syncOperateByInstruction current: %d new %d", m_operateByInstruction, operateByInstruction);
397
398
    if (m_operateByInstruction == operateByInstruction)
        return;
399
    QTC_ASSERT(m_accessible, return);
400
    m_operateByInstruction = operateByInstruction;
401
402
    postCommand(m_operateByInstruction ? QByteArray("l-t") : QByteArray("l+t"));
    postCommand(m_operateByInstruction ? QByteArray("l-s") : QByteArray("l+s"));
403
404
}

405
406
407
408
409
410
void CdbEngine::syncVerboseLog(bool verboseLog)
{
    if (m_verboseLog == verboseLog)
        return;
    QTC_ASSERT(m_accessible, return);
    m_verboseLog = verboseLog;
411
    postCommand(m_verboseLog ? QByteArray("!sym noisy") : QByteArray("!sym quiet"));
412
413
}

414
bool CdbEngine::canHandleToolTip(const DebuggerToolTipContext &context) const
415
{
hjk's avatar
hjk committed
416
417
418
419
420
    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;
421
422
423
}

// Determine full path to the CDB extension library.
424
QString CdbEngine::extensionLibraryName(bool is64Bit)
425
426
427
428
{
    // Determine extension lib name and path to use
    QString rc;
    QTextStream(&rc) << QFileInfo(QCoreApplication::applicationDirPath()).path()
hjk's avatar
hjk committed
429
                     << "/lib/" << (is64Bit ? QT_CREATOR_CDB_EXT "64" : QT_CREATOR_CDB_EXT "32")
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
                     << '/' << 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;
}

471
// Start the console stub with the sub process. Continue in consoleStubProcessStarted.
472
bool CdbEngine::startConsole(const DebuggerRunParameters &sp, QString *errorMessage)
473
474
475
{
    if (debug)
        qDebug("startConsole %s", qPrintable(sp.executable));
476
477
    m_consoleStub.reset(new ConsoleProcess);
    m_consoleStub->setMode(ConsoleProcess::Suspend);
478
479
480
481
482
483
    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);
484
    m_consoleStub->setWorkingDirectory(sp.workingDirectory);
485
486
    if (sp.environment.size())
        m_consoleStub->setEnvironment(sp.environment);
487
    if (!m_consoleStub->start(sp.executable, sp.processArgs)) {
488
        *errorMessage = tr("The console process \"%1\" could not be started.").arg(sp.executable);
489
490
491
492
493
        return false;
    }
    return true;
}

494
void CdbEngine::consoleStubError(const QString &msg)
495
{
496
    if (debug)
497
498
499
500
        qDebug("consoleStubProcessMessage() in %s %s", stateName(state()), qPrintable(msg));
    if (state() == EngineSetupRequested) {
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
501
    } else {
502
503
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
        notifyEngineIll();
504
    }
505
    Core::AsynchronousMessageBox::critical(tr("Debugger Error"), msg);
506
507
508
509
510
511
512
}

void CdbEngine::consoleStubProcessStarted()
{
    if (debug)
        qDebug("consoleStubProcessStarted() PID=%lld", m_consoleStub->applicationPID());
    // Attach to console process.
513
    DebuggerRunParameters attachParameters = runParameters();
514
515
516
517
    attachParameters.executable.clear();
    attachParameters.processArgs.clear();
    attachParameters.attachPID = m_consoleStub->applicationPID();
    attachParameters.startMode = AttachExternal;
518
    attachParameters.useTerminal = false;
519
520
521
522
    showMessage(QString::fromLatin1("Attaching to %1...").arg(attachParameters.attachPID), LogMisc);
    QString errorMessage;
    if (!launchCDB(attachParameters, &errorMessage)) {
        showMessage(errorMessage, LogError);
523
        Core::AsynchronousMessageBox::critical(tr("Failed to Start the Debugger"), errorMessage);
524
525
526
527
528
529
530
531
532
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
    }
}

void CdbEngine::consoleStubExited()
{
}

533
534
void CdbEngine::createFullBacktrace()
{
535
    postBuiltinCommand("~*kp", CB(handleCreateFullBackTrace));
536
537
}

538
void CdbEngine::handleCreateFullBackTrace(const CdbResponse &response)
539
{
540
    Internal::openTextEditor(QLatin1String("Backtrace $"), QLatin1String(response.joinedReply()));
541
542
}

543
544
545
546
547
void CdbEngine::setupEngine()
{
    if (debug)
        qDebug(">setupEngine");

548
549
550
    init();
    if (!m_logTime.elapsed())
        m_logTime.start();
551
552
553
554
555
    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.
556
557
558
    const DebuggerRunParameters &rp = runParameters();
    const bool launchConsole = isCreatorConsole(rp);
    m_effectiveStartMode = launchConsole ? AttachExternal : rp.startMode;
559
    const bool ok = launchConsole ?
560
561
                startConsole(runParameters(), &errorMessage) :
                launchCDB(runParameters(), &errorMessage);
562
563
564
565
    if (debug)
        qDebug("<setupEngine ok=%d", ok);
    if (!ok) {
        showMessage(errorMessage, LogError);
566
        Core::AsynchronousMessageBox::critical(tr("Failed to Start the Debugger"), errorMessage);
567
568
569
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
    }
570
571
572
573
574

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

575
576
577
578
579
    WatchHandler *wh = watchHandler();
    wh->addTypeFormats("QString", stringFormats);
    wh->addTypeFormats("QString *", stringFormats);
    wh->addTypeFormats("QByteArray", stringFormats);
    wh->addTypeFormats("QByteArray *", stringFormats);
580
    wh->addTypeFormats("std__basic_string", stringFormats);  // Python dumper naming convention for std::[w]string
581
582
583
584

    DisplayFormats imageFormats;
    imageFormats.append(SimpleFormat);
    imageFormats.append(EnhancedFormat);
585
586
    wh->addTypeFormats("QImage", imageFormats);
    wh->addTypeFormats("QImage *", imageFormats);
587
588
}

589
bool CdbEngine::launchCDB(const DebuggerRunParameters &sp, QString *errorMessage)
590
591
592
{
    if (debug)
        qDebug("launchCDB startMode=%d", sp.startMode);
593
    const QChar blank(QLatin1Char(' '));
594
    // Start engine which will run until initial breakpoint:
595
    // Determine binary (force MSVC), extension lib name and path to use
596
597
    // The extension is passed as relative name with the path variable set
    //(does not work with absolute path names)
hjk's avatar
hjk committed
598
    const QString executable = sp.debuggerCommand;
599
600
601
602
603
    if (executable.isEmpty()) {
        *errorMessage = tr("There is no CDB executable specified.");
        return false;
    }

hjk's avatar
hjk committed
604
605
    bool cdbIs64Bit = Utils::is64BitWindowsBinary(executable);
    if (!cdbIs64Bit)
606
        m_wow64State = noWow64Stack;
hjk's avatar
hjk committed
607
    const QFileInfo extensionFi(CdbEngine::extensionLibraryName(cdbIs64Bit));
608
    if (!extensionFi.isFile()) {
609
610
        *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
611
                                            "https://code.qt.io/cgit/qt-creator/binary-artifacts.git/.").
612
613
614
                arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
        return false;
    }
615
    const QString extensionFileName = extensionFi.fileName();
616
617
    // Prepare arguments
    QStringList arguments;
618
    const bool isRemote = sp.startMode == AttachToRemoteServer;
619
620
621
622
623
    if (isRemote) { // Must be first
        arguments << QLatin1String("-remote") << sp.remoteChannel;
    } else {
        arguments << (QLatin1String("-a") + extensionFileName);
    }
624
625
626
627
    // Source line info/No terminal breakpoint / Pull extension
    arguments << QLatin1String("-lines") << QLatin1String("-G")
    // register idle (debuggee stop) notification
              << QLatin1String("-c")
628
              << QLatin1String(".idle_cmd ") + QString::fromLatin1(m_extensionCommandPrefixBA) + QLatin1String("idle");
629
630
    if (sp.useTerminal) // Separate console
        arguments << QLatin1String("-2");
hjk's avatar
hjk committed
631
    if (boolSetting(IgnoreFirstChanceAccessViolation))
632
        arguments << QLatin1String("-x");
633

hjk's avatar
hjk committed
634
    const QStringList &symbolPaths = stringListSetting(CdbSymbolPaths);
635
    if (!symbolPaths.isEmpty())
hjk's avatar
hjk committed
636
        arguments << QLatin1String("-y") << symbolPaths.join(QLatin1Char(';'));
hjk's avatar
hjk committed
637
    const QStringList &sourcePaths = stringListSetting(CdbSourcePaths);
638
    if (!sourcePaths.isEmpty())
hjk's avatar
hjk committed
639
        arguments << QLatin1String("-srcpath") << sourcePaths.join(QLatin1Char(';'));
640

641
    // Compile argument string preserving quotes
hjk's avatar
hjk committed
642
    QString nativeArguments = stringSetting(CdbAdditionalArguments);
643
644
645
    switch (sp.startMode) {
    case StartInternal:
    case StartExternal:
646
647
        if (!nativeArguments.isEmpty())
            nativeArguments.push_back(blank);
648
        QtcProcess::addArgs(&nativeArguments, QStringList(QDir::toNativeSeparators(sp.executable)));
649
        break;
650
    case AttachToRemoteServer:
651
        break;
652
    case AttachExternal:
653
    case AttachCrashedExternal:
654
        arguments << QLatin1String("-p") << QString::number(sp.attachPID);
655
        if (sp.startMode == AttachCrashedExternal) {
656
            arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g");
657
        } else {
658
            if (isCreatorConsole(runParameters()))
659
660
                arguments << QLatin1String("-pr") << QLatin1String("-pb");
        }
661
        break;
662
663
664
    case AttachCore:
        arguments << QLatin1String("-z") << sp.coreFile;
        break;
665
666
667
668
    default:
        *errorMessage = QString::fromLatin1("Internal error: Unsupported start mode %1.").arg(sp.startMode);
        return false;
    }
669
670
671
672
673
674
    if (!sp.processArgs.isEmpty()) { // Complete native argument string.
        if (!nativeArguments.isEmpty())
            nativeArguments.push_back(blank);
        nativeArguments += sp.processArgs;
    }

675
676
    const QString msg = QString::fromLatin1("Launching %1 %2\nusing %3 of %4.").
            arg(QDir::toNativeSeparators(executable),
hjk's avatar
hjk committed
677
                arguments.join(blank) + blank + nativeArguments,
678
679
680
681
682
                QDir::toNativeSeparators(extensionFi.absoluteFilePath()),
                extensionFi.lastModified().toString(Qt::SystemLocaleShortDate));
    showMessage(msg, LogMisc);

    m_outputBuffer.clear();
683
    m_autoBreakPointCorrection = false;
684
685
686
687
    const QStringList environment = sp.environment.size() == 0 ?
                                    QProcessEnvironment::systemEnvironment().toStringList() :
                                    sp.environment.toStringList();
    m_process.setEnvironment(mergeEnvironment(environment, extensionFi.absolutePath()));
688
689
    if (!sp.workingDirectory.isEmpty())
        m_process.setWorkingDirectory(sp.workingDirectory);
690

691
#ifdef Q_OS_WIN
692
693
    if (!nativeArguments.isEmpty()) // Appends
        m_process.setNativeArguments(nativeArguments);
694
#endif
695
696
697
698
699
700
    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
701
702

    const unsigned long pid = Utils::qPidToPid(m_process.pid());
703
704
705
    showMessage(QString::fromLatin1("%1 running as %2").
                arg(QDir::toNativeSeparators(executable)).arg(pid), LogMisc);
    m_hasDebuggee = true;
706
707
708
709
    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();
710
        postCommand(loadCommand);
711
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk")
712
713
        notifyEngineSetupOk();
    }
714
715
716
717
718
    return true;
}

void CdbEngine::setupInferior()
{
719
720
    if (debug)
        qDebug("setupInferior");
721
722
    const DebuggerRunParameters &rp = runParameters();
    if (!rp.commandsAfterConnect.isEmpty())
723
        postCommand(rp.commandsAfterConnect);
724
725
726
    // QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
    // (attemptBreakpointSynchronization() will be directly called then)
    attemptBreakpointSynchronization();
727
    if (rp.breakOnMain) {
728
        const BreakpointParameters bp(BreakpointAtMain);
729
        postBuiltinCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings,
730
                                            BreakpointModelId(quint16(-1)), true),
731
                           CB(handleBreakInsert));
732
    }
733
734
735
    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
736
    postCommand(m_extensionCommandPrefixBA + "setparameter maxStringLength="
hjk's avatar
hjk committed
737
                + action(MaximalStringLength)->value().toByteArray()
738
                + " maxStackDepth="
739
740
                + action(MaximalStackDepth)->value().toByteArray());
    postExtensionCommand("pid", QByteArray(), CB(handlePid));
741
742
}

743
744
745
746
747
748
749
750
751
752
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:
753
754
755
        return "MSVCR110";
    case Abi::WindowsMsvc2013Flavor:
        return "MSVCR120";
Joerg Bornemann's avatar
Joerg Bornemann committed
756
757
    case Abi::WindowsMsvc2015Flavor:
        return "MSVCR140";
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
    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;
}

776
777
void CdbEngine::runEngine()
{
778
779
    if (debug)
        qDebug("runEngine");
780

hjk's avatar
hjk committed
781
    const QStringList breakEvents = stringListSetting(CdbBreakEvents);
782
    foreach (const QString &breakEvent, breakEvents)
783
        postCommand(QByteArray("sxe ") + breakEvent.toLatin1());
784
785
    // Break functions: each function must be fully qualified,
    // else the debugger will slow down considerably.
hjk's avatar
hjk committed
786
    if (boolSetting(CdbBreakOnCrtDbgReport)) {
787
        const QByteArray module = msvcRunTime(runParameters().toolChainAbi.osFlavor());
788
        const QByteArray debugModule = module + 'D';
789
        const QByteArray wideFunc = QByteArray(CdbOptionsPage::crtDbgReport).append('W');
790
        postBuiltinCommand(breakAtFunctionCommand(CdbOptionsPage::crtDbgReport, module),
791
                           CB(handleBreakInsert));
792
        postBuiltinCommand(breakAtFunctionCommand(wideFunc, module),
793
                           CB(handleBreakInsert));
794
        postBuiltinCommand(breakAtFunctionCommand(CdbOptionsPage::crtDbgReport, debugModule),
795
                           CB(handleBreakInsert));
796
        postBuiltinCommand(breakAtFunctionCommand(wideFunc, debugModule),
797
                           CB(handleBreakInsert));
798
    }
hjk's avatar
hjk committed
799
    if (boolSetting(BreakOnWarning)) {
800
        postBuiltinCommand("bm /( QtCored4!qWarning",
801
                           CB(handleBreakInsert)); // 'bm': All overloads.
802
        postBuiltinCommand("bm /( Qt5Cored!QMessageLogger::warning",
803
                           CB(handleBreakInsert));
804
    }
hjk's avatar
hjk committed
805
    if (boolSetting(BreakOnFatal)) {
806
        postBuiltinCommand("bm /( QtCored4!qFatal",
807
                           CB(handleBreakInsert)); // 'bm': All overloads.
808
        postBuiltinCommand("bm /( Qt5Cored!QMessageLogger::fatal",
809
                           CB(handleBreakInsert));
810
    }
811
    if (runParameters().startMode == AttachCore) {
812
        QTC_ASSERT(!m_coreStopReason.isNull(), return; );
hjk's avatar
hjk committed
813
        notifyEngineRunOkAndInferiorUnrunnable();
814
815
        processStop(*m_coreStopReason, false);
    } else {
816
        doContinueInferior();
817
    }
818
819
}

820
821
822
823
824
bool CdbEngine::commandsPending() const
{
    return !m_builtinCommandQueue.isEmpty() || !m_extensionCommandQueue.isEmpty();
}

825
826
827
828
829
830
831
832
833
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");
834
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
835
836
837
        notifyInferiorShutdownOk();
        return;
    }
838

839
    if (m_accessible) { // except console.
840
        if (runParameters().startMode == AttachExternal || runParameters().startMode == AttachCrashedExternal)
841
            detachDebugger();
842
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
843
844
        notifyInferiorShutdownOk();
    } else {
845
846
847
848
849
850
851
852
853
854
855
856
857
        // 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;
        }
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
        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)
873
874
875
876
        qDebug("CdbEngine::shutdownEngine in state '%s', process running %d,"
               "accessible=%d,commands pending=%d",
               stateName(state()), isCdbProcessRunning(), m_accessible,
               commandsPending());
877
878

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

884
    // No longer trigger anything from messages
885
    m_ignoreCdbOutput = true;
886
887
    // Go for kill if there are commands pending.
    if (m_accessible && !commandsPending()) {
888
        // detach (except console): Wait for debugger to finish.
889
        if (runParameters().startMode == AttachExternal || runParameters().startMode == AttachCrashedExternal)
890
            detachDebugger();
891
        // Remote requires a bit more force to quit.
892
        if (m_effectiveStartMode == AttachToRemoteServer) {
893
894
            postCommand(m_extensionCommandPrefixBA + "shutdownex");
            postCommand("qq");
895
        } else {
896
            postCommand("q");
897
898
899
        }
    } else {
        // Remote process. No can do, currently
900
        SynchronousProcess::stopProcess(m_process);
901
902
903
    }
}

904
905
906
907
908
909
910
911
912
913
914
915
916
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();
    }
}

917
918
919
void CdbEngine::processFinished()
{
    if (debug)
920
921
        qDebug("CdbEngine::processFinished %dms '%s' (exit state=%d, ex=%d)",
               elapsedLogTime(), stateName(state()), m_process.exitStatus(), m_process.exitCode());
922

923
924
925
    notifyDebuggerProcessFinished(m_process.exitCode(),
                                  m_process.exitStatus(),
                                  QLatin1String("CDB"));
926
927
928
929
}

void CdbEngine::detachDebugger()
{
930
    postCommand(".detach");
931
932
}

933
934
935
936
937
static inline bool isWatchIName(const QByteArray &iname)
{
    return iname.startsWith("watch");
}

hjk's avatar
hjk committed
938
bool CdbEngine::hasCapability(unsigned cap) const
939
{
hjk's avatar
hjk committed
940
941
    return cap & (DisassemblerCapability | RegisterCapability
           | ShowMemoryCapability
942
           |WatchpointByAddressCapability|JumpToLineCapability|AddWatcherCapability|WatchWidgetsCapability
943
           |ReloadModuleCapability
944
           |BreakOnThrowAndCatchCapability // Sort-of: Can break on throw().
945
           |BreakConditionCapability|TracePointCapability
946
           |BreakModuleCapability
947
           |CreateFullBacktraceCapability
948
           |OperateByInstructionCapability
949
           |RunToLineCapability
950
951
           |MemoryAddressCapability
           |AdditionalQmlStackCapability);
952
953
954
955
}

void CdbEngine::executeStep()
{
956
957
    if (!m_operateByInstruction)
        m_sourceStepInto = true; // See explanation at handleStackTrace().
958
    postCommand(QByteArray("t")); // Step into-> t (trace)
959
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
960
961
962
963
964
    notifyInferiorRunRequested();
}

void CdbEngine::executeStepOut()
{
965
    postCommand(QByteArray("gu")); // Step out-> gu (go up)
966
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
967
968
969
970
971
    notifyInferiorRunRequested();
}

void CdbEngine::executeNext()
{
972
    postCommand(QByteArray("p")); // Step over -> p
973
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
    notifyInferiorRunRequested();
}

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

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

void CdbEngine::continueInferior()
{
989
    STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorRunRequested")