cdbengine.cpp 92.7 KB
Newer Older
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6
7
8
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
con's avatar
con committed
9
** No Commercial Usage
10
**
con's avatar
con committed
11
12
13
14
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
15
16
17
18
19
20
21
22
23
24
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
con's avatar
con committed
25
26
27
28
29
30
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
31
32
33
**
**************************************************************************/

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

#include <coreplugin/icore.h>
60
#include <texteditor/itexteditor.h>
61
#include <projectexplorer/toolchain.h>
62
#include <projectexplorer/projectexplorerconstants.h>
63

64
#include <utils/synchronousprocess.h>
65
66
67
#include <utils/winutils.h>
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
68
#include <utils/consoleprocess.h>
69
70
71
72
73
74
75

#include <QtCore/QCoreApplication>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <QtCore/QTextStream>
#include <QtCore/QDateTime>
76
#include <QtGui/QToolTip>
77
78
#include <QtGui/QMainWindow>
#include <QtGui/QMessageBox>
79
80
81
82
83
84
85
86

#ifdef Q_OS_WIN
#    include <utils/winutils.h>
#    include "dbgwinutils.h"
#endif

#include <cctype>

87
88
Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgent*)
Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgent*)
89
90

enum { debug = 0 };
91
enum { debugLocals = 0 };
92
enum { debugWatches = 0 };
93
94
95
enum { debugBreakpoints = 0 };

#if 0
96
#  define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line);
97
#else
98
#  define STATE_DEBUG(state, func, line, notifyFunc)
99
100
#endif

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*!
    \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
    \o Notify the engine about the state of the debugging session:
        \list
        \o idle: (hooked up with .idle_cmd) debuggee stopped
        \o accessible: Debuggee stopped, cdb.exe accepts commands
        \o inaccessible: Debuggee runs, no way to post commands
        \o session active/inactive: Lost debuggee, terminating.
        \endlist
    \o Hook up with output/event callbacks and produce formatted output to be able
       to catch application output and exceptions.
    \o Provide some extension commands that produce output in a standardized (GDBMI)
      format that ends up in handleExtensionMessage(), for example:
      \list
      \o pid     Return debuggee pid for interrupting.
      \o locals  Print locals from SymbolGroup
      \o expandLocals Expand locals in symbol group
      \o registers, modules, threads
      \endlist
   \endlist

   Debugger commands can be posted by calling:

   \list

    \o postCommand(): Does not expect a reply
    \o postBuiltinCommand(): Run a builtin-command producing free-format, multiline output
       that is captured by enclosing it in special tokens using the 'echo' command and
       then invokes a callback with a CdbBuiltinCommand structure.
    \o postExtensionCommand(): Run a command provided by the extension producing
       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).
*/
155

156
157
using namespace ProjectExplorer;

158
namespace Debugger {
159
namespace Internal {
160

161
162
static const char localsPrefixC[] = "local.";

hjk's avatar
hjk committed
163
164
struct MemoryViewCookie
{
165
    explicit MemoryViewCookie(MemoryAgent *a = 0, QObject *e = 0,
166
                              quint64 addr = 0, quint64 l = 0) :
hjk's avatar
hjk committed
167
168
        agent(a), editorToken(e), address(addr), length(l)
    {}
169

170
    MemoryAgent *agent;
171
172
173
174
175
    QObject *editorToken;
    quint64 address;
    quint64 length;
};

176
} // namespace Internal
177
178
} // namespace Debugger

179
Q_DECLARE_METATYPE(Debugger::Internal::MemoryViewCookie)
180
181

namespace Debugger {
182
namespace Internal {
183

184
static inline bool isConsole(const DebuggerStartParameters &sp)
hjk's avatar
hjk committed
185
186
187
188
{
    return (sp.startMode == StartInternal || sp.startMode == StartExternal)
        && sp.useTerminal;
}
189

hjk's avatar
hjk committed
190
191
static QMessageBox *
nonModalMessageBox(QMessageBox::Icon icon, const QString &title, const QString &text)
192
193
194
195
196
197
198
199
{
    QMessageBox *mb = new QMessageBox(icon, title, text, QMessageBox::Ok,
                                      debuggerCore()->mainWindow());
    mb->setAttribute(Qt::WA_DeleteOnClose);
    mb->show();
    return mb;
}

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
// Base data structure for command queue entries with callback
struct CdbCommandBase
{
    typedef CdbEngine::BuiltinCommandHandler CommandHandler;

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

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

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

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

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

    CdbBuiltinCommand() {}
    CdbBuiltinCommand(const QByteArray  &cmd, int token, unsigned flags,
                      CommandHandler h,
                      unsigned nc, const QVariant &cookie) :
hjk's avatar
hjk committed
238
239
        CdbCommandBase(cmd, token, flags, nc, cookie), handler(h)
    {}
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303


    QByteArray joinedReply() const;

    CommandHandler handler;
    QList<QByteArray> reply;
};

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

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

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

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

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

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

// Accessed by RunControlFactory
304
305
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp,
    DebuggerEngine *masterEngine, QString *errorMessage)
306
307
308
{
#ifdef Q_OS_WIN
    CdbOptionsPage *op = CdbOptionsPage::instance();
309
310
    if (!op || !op->options()->isValid() || !validMode(sp.startMode)) {
        *errorMessage = QLatin1String("Internal error: Invalid start parameters passed for thre CDB engine.");
311
312
        return 0;
    }
313
    return new CdbEngine(sp, masterEngine, op->options());
314
#else
315
    Q_UNUSED(masterEngine)
316
317
    Q_UNUSED(sp)
#endif
318
    *errorMessage = QString::fromLatin1("Unsupported debug mode");
319
320
321
322
323
324
    return 0;
}

bool isCdbEngineEnabled()
{
#ifdef Q_OS_WIN
325
    return CdbOptionsPage::instance() && CdbOptionsPage::instance()->options()->isValid();
326
327
328
329
330
#else
    return false;
#endif
}

331
static inline QString msgNoCdbBinaryForToolChain(const ProjectExplorer::Abi &tc)
332
{
333
334
335
    return CdbEngine::tr("There is no CDB binary available for binaries in format '%1'").arg(tc.toString());
}

336
337
338
339
340
341
342
343
344
345
346
347
static QString cdbBinary(const DebuggerStartParameters &sp)
{
    if (!sp.debuggerCommand.isEmpty()) {
        // Do not use a GDB binary if we got started for a project with MinGW runtime.
        const bool abiMatch = sp.toolChainAbi.os() == ProjectExplorer::Abi::WindowsOS
                    && sp.toolChainAbi.osFlavor() == ProjectExplorer::Abi::WindowsMsvcFlavor;
        if (abiMatch)
            return sp.debuggerCommand;
    }
    return debuggerCore()->debuggerForAbi(sp.toolChainAbi, CdbEngineType);
}

348
349
350
351
bool checkCdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check)
{
#ifdef Q_OS_WIN
    if (!isCdbEngineEnabled()) {
352
353
        check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine required for %1 is currently disabled.").
                           arg(sp.toolChainAbi.toString()));
354
355
356
        check->settingsCategory = QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY);
        check->settingsPage = CdbOptionsPage::settingsId();
        return false;
357
    }
358
359

    if (!validMode(sp.startMode)) {
360
        check->errorDetails.push_back(CdbEngine::tr("The CDB engine does not support start mode %1.").arg(sp.startMode));
361
362
363
364
        return false;
    }

    if (sp.toolChainAbi.binaryFormat() != Abi::PEFormat || sp.toolChainAbi.os() != Abi::WindowsOS) {
365
366
        check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine does not support the %1 ABI.").
                                      arg(sp.toolChainAbi.toString()));
367
368
        return false;
    }
369
370
371
372
373
374
375
376

    if (cdbBinary(sp).isEmpty()) {
        check->errorDetails.push_back(msgNoCdbBinaryForToolChain(sp.toolChainAbi));
        check->settingsCategory = QLatin1String(ProjectExplorer::Constants::TOOLCHAIN_SETTINGS_CATEGORY);
        check->settingsPage = QLatin1String(ProjectExplorer::Constants::TOOLCHAIN_SETTINGS_CATEGORY);
        return false;
    }

377
378
379
    return true;
#else
    Q_UNUSED(sp);
380
    check->errorDetails.push_back(QString::fromLatin1("Unsupported debug mode"));
381
382
    return false;
#endif
383
384
}

385
void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
386
{
387
#ifdef Q_OS_WIN
388
    opts->push_back(new CdbOptionsPage);
389
390
391
#else
    Q_UNUSED(opts);
#endif
392
393
394
395
396
397
}

#define QT_CREATOR_CDB_EXT "qtcreatorcdbext"

static inline Utils::SavedAction *theAssemblerAction()
{
398
    return debuggerCore()->action(OperateByInstruction);
399
400
}

401
402
403
CdbEngine::CdbEngine(const DebuggerStartParameters &sp,
        DebuggerEngine *masterEngine, const OptionsPtr &options) :
    DebuggerEngine(sp, masterEngine),
404
405
406
    m_creatorExtPrefix("<qtcreatorcdbext>|"),
    m_tokenPrefix("<token>"),
    m_options(options),
407
    m_effectiveStartMode(NoStartMode),
408
409
410
411
412
413
414
415
416
417
    m_inferiorPid(0),
    m_accessible(false),
    m_specialStopMode(NoSpecialStop),
    m_nextCommandToken(0),
    m_currentBuiltinCommandIndex(-1),
    m_extensionCommandPrefixBA("!"QT_CREATOR_CDB_EXT"."),
    m_operateByInstructionPending(true),
    m_operateByInstruction(true), // Default CDB setting
    m_notifyEngineShutdownOnTermination(false),
    m_hasDebuggee(false),
418
    m_elapsedLogTime(0),
419
    m_sourceStepInto(false),
420
    m_watchPointX(0),
421
422
    m_watchPointY(0),
    m_ignoreCdbOutput(false)
423
{
424
    connect(theAssemblerAction(), SIGNAL(triggered(bool)), this, SLOT(operateByInstructionTriggered(bool)));
425
426
427
428
429
430
431
432

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

433
434
435
436
437
438
439
440
void CdbEngine::init()
{
    m_effectiveStartMode = NoStartMode;
    m_inferiorPid = 0;
    m_accessible = false;
    m_specialStopMode = NoSpecialStop;
    m_nextCommandToken  = 0;
    m_currentBuiltinCommandIndex = -1;
441
    m_operateByInstructionPending = theAssemblerAction()->isChecked();
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
    m_operateByInstruction = true; // Default CDB setting
    m_notifyEngineShutdownOnTermination = false;
    m_hasDebuggee = false;
    m_sourceStepInto = false;
    m_watchPointX = m_watchPointY = 0;
    m_ignoreCdbOutput = false;

    m_outputBuffer.clear();
    m_builtinCommandQueue.clear();
    m_extensionCommandQueue.clear();
    m_extensionMessageBuffer.clear();
    m_pendingBreakpointMap.clear();
    QTC_ASSERT(m_process.state() != QProcess::Running, Utils::SynchronousProcess::stopProcess(m_process); )
}

457
458
459
460
461
462
CdbEngine::~CdbEngine()
{
}

void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
{
463
464
465
466
467
468
469
470
471
472
    if (state() == InferiorStopOk) {
        syncOperateByInstruction(operateByInstruction);
    } else {
        // To be set next time session becomes accessible
        m_operateByInstructionPending = operateByInstruction;
    }
}

void CdbEngine::syncOperateByInstruction(bool operateByInstruction)
{
473
474
    if (debug)
        qDebug("syncOperateByInstruction current: %d new %d", m_operateByInstruction, operateByInstruction);
475
476
477
478
479
480
    if (m_operateByInstruction == operateByInstruction)
        return;
    QTC_ASSERT(m_accessible, return; )
    m_operateByInstruction = operateByInstruction;
    postCommand(m_operateByInstruction ? QByteArray("l-t") : QByteArray("l+t"), 0);
    postCommand(m_operateByInstruction ? QByteArray("l-s") : QByteArray("l+s"), 0);
481
482
}

483
bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
484
485
                                     TextEditor::ITextEditor *editor,
                                     const DebuggerToolTipContext &contextIn)
486
{
487
488
489
490
    if (debug)
        qDebug() << Q_FUNC_INFO;
    // Need a stopped debuggee and a cpp file in a valid frame
    if (state() != InferiorStopOk || !isCppEditor(editor) || stackHandler()->currentIndex() < 0)
491
        return false;
492
493
494
    // Determine expression and function
    int line;
    int column;
495
496
    DebuggerToolTipContext context = contextIn;
    const QString exp = cppExpressionAt(editor, context.position, &line, &column, &context.function);
497
    // Are we in the current stack frame
498
    if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function)
499
        return false;
500
501
    // No numerical or any other expressions [yet]
    if (!(exp.at(0).isLetter() || exp.at(0) == QLatin1Char('_')))
502
        return false;
503
    const QByteArray iname = QByteArray(localsPrefixC) + exp.toAscii();
504
    const QModelIndex index = watchHandler()->itemIndex(iname);
505
506
507
508
509
510
511
    if (!index.isValid())
        return false;
    DebuggerTreeViewToolTipWidget *tw = new DebuggerTreeViewToolTipWidget;
    tw->setContext(context);
    tw->setDebuggerModel(LocalsWatch);
    tw->setExpression(exp);
    tw->acquireEngine(this);
512
    DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw);
513
    return true;
514
515
516
}

// Determine full path to the CDB extension library.
517
QString CdbEngine::extensionLibraryName(bool is64Bit)
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
{
    // Determine extension lib name and path to use
    QString rc;
    QTextStream(&rc) << QFileInfo(QCoreApplication::applicationDirPath()).path()
                     << "/lib/" << (is64Bit ? QT_CREATOR_CDB_EXT"64" : QT_CREATOR_CDB_EXT"32")
                     << '/' << 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;
}

564
565
566
567
568
569
570
571
572
573
574
575
576
577
// Start the console stub with the sub process. Continue in consoleStubProcessStarted.
bool CdbEngine::startConsole(const DebuggerStartParameters &sp, QString *errorMessage)
{
    if (debug)
        qDebug("startConsole %s", qPrintable(sp.executable));
    m_consoleStub.reset(new Utils::ConsoleProcess);
    m_consoleStub->setMode(Utils::ConsoleProcess::Suspend);
    connect(m_consoleStub.data(), SIGNAL(processMessage(QString, bool)),
            SLOT(consoleStubMessage(QString, bool)));
    connect(m_consoleStub.data(), SIGNAL(processStarted()),
            SLOT(consoleStubProcessStarted()));
    connect(m_consoleStub.data(), SIGNAL(wrapperStopped()),
            SLOT(consoleStubExited()));
    m_consoleStub->setWorkingDirectory(sp.workingDirectory);
578
579
    if (sp.environment.size())
        m_consoleStub->setEnvironment(sp.environment);
580
581
582
583
584
585
586
587
    if (!m_consoleStub->start(sp.executable, sp.processArgs)) {
        *errorMessage = tr("The console process '%1' could not be started.").arg(sp.executable);
        return false;
    }
    return true;
}

void CdbEngine::consoleStubMessage(const QString &msg, bool isError)
588
{
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
    if (debug)
        qDebug("consoleStubProcessMessage() in %s error=%d %s", stateName(state()), isError, qPrintable(msg));
    if (isError) {
        if (state() == EngineSetupRequested) {
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
            notifyEngineSetupFailed();
        } else {
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
            notifyEngineIll();
        }
        nonModalMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg);
    } else {
        showMessage(msg, AppOutput);
    }
}

void CdbEngine::consoleStubProcessStarted()
{
    if (debug)
        qDebug("consoleStubProcessStarted() PID=%lld", m_consoleStub->applicationPID());
    // Attach to console process.
    DebuggerStartParameters attachParameters = startParameters();
    attachParameters.executable.clear();
    attachParameters.processArgs.clear();
    attachParameters.attachPID = m_consoleStub->applicationPID();
    attachParameters.startMode = AttachExternal;
    showMessage(QString::fromLatin1("Attaching to %1...").arg(attachParameters.attachPID), LogMisc);
    QString errorMessage;
    if (!launchCDB(attachParameters, &errorMessage)) {
        showMessage(errorMessage, LogError);
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
    }
}

void CdbEngine::consoleStubExited()
{
}

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

637
638
639
    init();
    if (!m_logTime.elapsed())
        m_logTime.start();
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
    QString errorMessage;
    // Console: Launch the stub with the suspended application and attach to it
    // CDB in theory has a command line option '-2' that launches a
    // console, too, but that immediately closes when the debuggee quits.
    // Use the Creator stub instead.
    const DebuggerStartParameters &sp = startParameters();
    const bool launchConsole = isConsole(sp);
    m_effectiveStartMode = launchConsole ? AttachExternal : sp.startMode;
    const bool ok = launchConsole ?
                startConsole(startParameters(), &errorMessage) :
                launchCDB(startParameters(), &errorMessage);
    if (debug)
        qDebug("<setupEngine ok=%d", ok);
    if (!ok) {
        showMessage(errorMessage, LogError);
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
    }
}

bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessage)
{
    if (debug)
        qDebug("launchCDB startMode=%d", sp.startMode);
664
    const QChar blank(QLatin1Char(' '));
665
    // Start engine which will run until initial breakpoint:
666
    // Determine binary (force MSVC), extension lib name and path to use
667
668
    // The extension is passed as relative name with the path variable set
    //(does not work with absolute path names)
669
    const QString executable = cdbBinary(sp);
670
671
672
673
674
675
676
677
678
679
680
681
    if (executable.isEmpty()) {
        *errorMessage = tr("There is no CDB executable specified.");
        return false;
    }

    const bool is64bit =
#ifdef Q_OS_WIN
            Utils::winIs64BitBinary(executable);
#else
            false;
#endif
    const QFileInfo extensionFi(CdbEngine::extensionLibraryName(is64bit));
682
683
684
685
686
    if (!extensionFi.isFile()) {
        *errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found.").
                arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
        return false;
    }
687
    const QString extensionFileName = extensionFi.fileName();
688
689
    // Prepare arguments
    QStringList arguments;
690
691
692
693
694
695
    const bool isRemote = sp.startMode == AttachToRemote;
    if (isRemote) { // Must be first
        arguments << QLatin1String("-remote") << sp.remoteChannel;
    } else {
        arguments << (QLatin1String("-a") + extensionFileName);
    }
696
697
698
699
700
701
702
703
704
705
706
    // Source line info/No terminal breakpoint / Pull extension
    arguments << QLatin1String("-lines") << QLatin1String("-G")
    // register idle (debuggee stop) notification
              << QLatin1String("-c")
              << QString::fromAscii(".idle_cmd " + m_extensionCommandPrefixBA + "idle");
    if (sp.useTerminal) // Separate console
        arguments << QLatin1String("-2");
    if (!m_options->symbolPaths.isEmpty())
        arguments << QLatin1String("-y") << m_options->symbolPaths.join(QString(QLatin1Char(';')));
    if (!m_options->sourcePaths.isEmpty())
        arguments << QLatin1String("-srcpath") << m_options->sourcePaths.join(QString(QLatin1Char(';')));
707
708
    // Compile argument string preserving quotes
    QString nativeArguments = m_options->additionalArguments;
709
710
711
    switch (sp.startMode) {
    case StartInternal:
    case StartExternal:
712
713
714
        if (!nativeArguments.isEmpty())
            nativeArguments.push_back(blank);
        nativeArguments += QDir::toNativeSeparators(sp.executable);
715
        break;
716
717
    case AttachToRemote:
        break;
718
    case AttachExternal:
719
    case AttachCrashedExternal:
720
721
722
723
724
725
726
727
        arguments << QLatin1String("-p") << QString::number(sp.attachPID);
        if (sp.startMode == AttachCrashedExternal)
            arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g");
        break;
    default:
        *errorMessage = QString::fromLatin1("Internal error: Unsupported start mode %1.").arg(sp.startMode);
        return false;
    }
728
729
730
731
732
733
    if (!sp.processArgs.isEmpty()) { // Complete native argument string.
        if (!nativeArguments.isEmpty())
            nativeArguments.push_back(blank);
        nativeArguments += sp.processArgs;
    }

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

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

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

void CdbEngine::setupInferior()
{
780
781
    if (debug)
        qDebug("setupInferior");
782
    attemptBreakpointSynchronization();
783
    postCommand("sxn 0x4000001f", 0); // Do not break on WowX86 exceptions.
784
785
786
787
788
    postExtensionCommand("pid", QByteArray(), 0, &CdbEngine::handlePid);
}

void CdbEngine::runEngine()
{
789
790
    if (debug)
        qDebug("runEngine");
791
792
793
    // Resume the threads frozen by the console stub.
    if (isConsole(startParameters()))
        postCommand("~* m", 0);
794
795
    foreach (const QString &breakEvent, m_options->breakEvents)
            postCommand(QByteArray("sxe ") + breakEvent.toAscii(), 0);
796
797
798
    postCommand("g", 0);
}

799
800
801
802
803
bool CdbEngine::commandsPending() const
{
    return !m_builtinCommandQueue.isEmpty() || !m_extensionCommandQueue.isEmpty();
}

804
805
806
807
808
809
810
811
812
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");
813
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
814
815
816
        notifyInferiorShutdownOk();
        return;
    }
817

818
    if (m_accessible) {
819
        if (m_effectiveStartMode == AttachExternal || m_effectiveStartMode == AttachCrashedExternal)
820
            detachDebugger();
821
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
822
823
        notifyInferiorShutdownOk();
    } else {
824
825
826
827
828
829
830
831
832
833
834
835
836
        // 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;
        }
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
        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)
852
853
854
855
        qDebug("CdbEngine::shutdownEngine in state '%s', process running %d,"
               "accessible=%d,commands pending=%d",
               stateName(state()), isCdbProcessRunning(), m_accessible,
               commandsPending());
856
857

    if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
858
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
859
860
861
862
        notifyEngineShutdownOk();
        return;
    }

863
    // No longer trigger anything from messages
864
    m_ignoreCdbOutput = true;
865
866
867
    // Go for kill if there are commands pending.
    if (m_accessible && !commandsPending()) {
        // detach: Wait for debugger to finish.
868
        if (m_effectiveStartMode == AttachExternal)
869
            detachDebugger();
870
        // Remote requires a bit more force to quit.
871
        if (m_effectiveStartMode == AttachToRemote) {
872
873
874
875
876
877
878
879
880
            postCommand(m_extensionCommandPrefixBA + "shutdownex", 0);
            postCommand("qq", 0);
        } else {
            postCommand("q", 0);
        }
        m_notifyEngineShutdownOnTermination = true;
        return;
    } else {
        // Remote process. No can do, currently
881
        m_notifyEngineShutdownOnTermination = true;
882
        Utils::SynchronousProcess::stopProcess(m_process);
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
        return;
    }
    // Lost debuggee, debugger should quit anytime now
    if (!m_hasDebuggee) {
        m_notifyEngineShutdownOnTermination = true;
        return;
    }
    interruptInferior();
}

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

    const bool crashed = m_process.exitStatus() == QProcess::CrashExit;
    if (crashed) {
        showMessage(tr("CDB crashed"), LogError); // not in your life.
    } else {
        showMessage(tr("CDB exited (%1)").arg(m_process.exitCode()), LogMisc);
    }

    if (m_notifyEngineShutdownOnTermination) {
        if (crashed) {
            if (debug)
                qDebug("notifyEngineIll");
911
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
912
913
            notifyEngineIll();
        } else {
914
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
915
916
917
            notifyEngineShutdownOk();
        }
    } else {
918
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSpontaneousShutdown")
919
920
921
922
923
924
925
926
927
        notifyEngineSpontaneousShutdown();
    }
}

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

928
929
930
931
932
static inline bool isWatchIName(const QByteArray &iname)
{
    return iname.startsWith("watch");
}

933
934
void CdbEngine::updateWatchData(const WatchData &dataIn,
                                const WatchUpdateFlags & flags)
935
{
936
937
938
    if (debug || debugLocals || debugWatches)
        qDebug("CdbEngine::updateWatchData() %dms accessible=%d %s incr=%d: %s",
               elapsedLogTime(), m_accessible, stateName(state()),
939
940
941
               flags.tryIncremental,
               qPrintable(dataIn.toString()));

942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
    if (!m_accessible) // Add watch data while running?
        return;

    // New watch item?
    if (isWatchIName(dataIn.iname) && dataIn.isValueNeeded()) {
        QByteArray args;
        ByteArrayInputStream str(args);
        str << dataIn.iname << " \"" << dataIn.exp << '"';
        postExtensionCommand("addwatch", args, 0,
                             &CdbEngine::handleAddWatch, 0,
                             qVariantFromValue(dataIn));
        return;
    }

    if (!dataIn.hasChildren && !dataIn.isValueNeeded()) {
957
        WatchData data = dataIn;
958
959
960
961
962
963
964
        data.setAllUnneeded();
        watchHandler()->insertData(data);
        return;
    }
    updateLocalVariable(dataIn.iname);
}

965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
void CdbEngine::handleAddWatch(const CdbExtensionCommandPtr &reply)
{
    WatchData item = qvariant_cast<WatchData>(reply->cookie);
    if (debugWatches)
        qDebug() << "handleAddWatch ok="  << reply->success << item.iname;
    if (reply->success) {
        updateLocalVariable(item.iname);
    } else {
        item.setError(tr("Unable to add expression"));
        watchHandler()->insertData(item);
        showMessage(QString::fromLatin1("Unable to add watch item '%1'/'%2': %3").
                    arg(QString::fromAscii(item.iname), QString::fromAscii(item.exp),
                        reply->errorMessage), LogError);
    }
}

981
982
void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const
{
983
984
    if (debuggerCore()->boolSetting(VerboseLog))
        str << blankSeparator << "-v";
985
986
987
988
989
990
991
992
993
994
    if (debuggerCore()->boolSetting(UseDebuggingHelpers))
        str << blankSeparator << "-c";
    const QByteArray typeFormats = watchHandler()->typeFormatRequests();
    if (!typeFormats.isEmpty())
        str << blankSeparator << "-T " << typeFormats;
    const QByteArray individualFormats = watchHandler()->individualFormatRequests();
    if (!individualFormats.isEmpty())
        str << blankSeparator << "-I " << individualFormats;
}

995
996
void CdbEngine::updateLocalVariable(const QByteArray &iname)
{
997
998
999
1000
    const bool isWatch = isWatchIName(iname);
    if (debugWatches)
        qDebug() << "updateLocalVariable watch=" << isWatch << iname;
    QByteArray localsArguments;