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), isBuiltin(true)
222
223
    {}

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

    int token;

234
    bool isBuiltin;
235
    CdbEngine::CommandHandler handler;
236

237
    CdbResponse response; // FIXME: remove.
238
239
};

240
QByteArray CdbResponse::joinedReply() const
241
{
242
    if (builtinReply.isEmpty())
243
244
        return QByteArray();
    QByteArray answer;
245
246
    answer.reserve(120  * builtinReply.size());
    foreach (const QByteArray &l, builtinReply) {
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
        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)
{
265
    return sm != NoStartMode;
266
267
268
}

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

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

#define QT_CREATOR_CDB_EXT "qtcreatorcdbext"

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

    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);
328
329
}

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

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

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

376
377
378
379
380
381
CdbEngine::~CdbEngine()
{
}

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

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

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

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

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

// Determine full path to the CDB extension library.
426
QString CdbEngine::extensionLibraryName(bool is64Bit)
427
428
429
430
{
    // Determine extension lib name and path to use
    QString rc;
    QTextStream(&rc) << QFileInfo(QCoreApplication::applicationDirPath()).path()
hjk's avatar
hjk committed
431
                     << "/lib/" << (is64Bit ? QT_CREATOR_CDB_EXT "64" : QT_CREATOR_CDB_EXT "32")
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
471
472
                     << '/' << 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;
}

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

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

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

void CdbEngine::consoleStubExited()
{
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

778
779
void CdbEngine::runEngine()
{
780
781
    if (debug)
        qDebug("runEngine");
782

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

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

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

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

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

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

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

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

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

void CdbEngine::detachDebugger()
{
932
    postCommand(".detach");
933
934
}

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

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

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

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

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