cdbengine.cpp 116 KB
Newer Older
1 2 3 4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
6
**
Eike Ziller's avatar
Eike Ziller committed
7
** Contact: http://www.qt-project.org/
8 9 10 11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12 13 14 15 16 17
** 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.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21 22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23 24 25 26 27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
28 29 30
**
**************************************************************************/

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

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

60 61
#include <TranslationUnit.h>

62
#include <coreplugin/icore.h>
63
#include <texteditor/itexteditor.h>
64
#include <projectexplorer/abi.h>
65
#include <projectexplorer/projectexplorerconstants.h>
66

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

#include <cplusplus/findcdbbreakpoint.h>
#include <cplusplus/CppDocument.h>
76
#include <cpptools/ModelManagerInterface.h>
77

78 79 80 81 82 83 84 85 86
#include <QCoreApplication>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
#include <QTextStream>
#include <QDateTime>
#include <QToolTip>
#include <QMainWindow>
#include <QMessageBox>
87 88 89

#include <cctype>

90 91
Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgent*)
Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgent*)
92 93

enum { debug = 0 };
94
enum { debugLocals = 0 };
95
enum { debugSourceMapping = 0 };
96
enum { debugWatches = 0 };
97 98
enum { debugBreakpoints = 0 };

hjk's avatar
hjk committed
99 100 101 102 103 104
enum HandleLocalsFlags
{
    PartialLocalsUpdate = 0x1,
    LocalsUpdateForNewFrame = 0x2
};

105
#if 0
106
#  define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line);
107
#else
108
#  define STATE_DEBUG(state, func, line, notifyFunc)
109 110
#endif

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 155 156 157 158 159 160 161 162 163 164
/*!
    \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).
*/
165

166 167
using namespace ProjectExplorer;

168
namespace Debugger {
169
namespace Internal {
170

171 172
static const char localsPrefixC[] = "local.";

hjk's avatar
hjk committed
173 174
struct MemoryViewCookie
{
175
    explicit MemoryViewCookie(MemoryAgent *a = 0, QObject *e = 0,
176
                              quint64 addr = 0, quint64 l = 0) :
hjk's avatar
hjk committed
177 178
        agent(a), editorToken(e), address(addr), length(l)
    {}
179

180
    MemoryAgent *agent;
181 182 183 184 185
    QObject *editorToken;
    quint64 address;
    quint64 length;
};

186 187 188 189 190 191 192 193 194
struct MemoryChangeCookie
{
    explicit MemoryChangeCookie(quint64 addr = 0, const QByteArray &d = QByteArray()) :
                               address(addr), data(d) {}

    quint64 address;
    QByteArray data;
};

195 196
struct ConditionalBreakPointCookie
{
197 198
    ConditionalBreakPointCookie(BreakpointModelId i = BreakpointModelId()) : id(i) {}
    BreakpointModelId id;
199 200 201
    GdbMi stopReason;
};

202
} // namespace Internal
203 204
} // namespace Debugger

205
Q_DECLARE_METATYPE(Debugger::Internal::MemoryViewCookie)
206
Q_DECLARE_METATYPE(Debugger::Internal::MemoryChangeCookie)
207
Q_DECLARE_METATYPE(Debugger::Internal::ConditionalBreakPointCookie)
208 209

namespace Debugger {
210
namespace Internal {
211

212
static inline bool isCreatorConsole(const DebuggerStartParameters &sp, const CdbOptions &o)
hjk's avatar
hjk committed
213
{
214 215
    return !o.cdbConsole && sp.useTerminal
           && (sp.startMode == StartInternal || sp.startMode == StartExternal);
hjk's avatar
hjk committed
216
}
217

hjk's avatar
hjk committed
218 219
static QMessageBox *
nonModalMessageBox(QMessageBox::Icon icon, const QString &title, const QString &text)
220 221 222 223 224 225 226 227
{
    QMessageBox *mb = new QMessageBox(icon, title, text, QMessageBox::Ok,
                                      debuggerCore()->mainWindow());
    mb->setAttribute(Qt::WA_DeleteOnClose);
    mb->show();
    return mb;
}

228 229 230 231 232 233 234 235 236 237 238 239 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
// 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
266 267
        CdbCommandBase(cmd, token, flags, nc, cookie), handler(h)
    {}
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 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329


    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 StartRemoteGdb:
        return false;
    default:
        break;
    }
    return true;
}

// Accessed by RunControlFactory
330 331
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp,
    DebuggerEngine *masterEngine, QString *errorMessage)
332 333 334
{
#ifdef Q_OS_WIN
    CdbOptionsPage *op = CdbOptionsPage::instance();
335 336
    if (!op || !op->options()->isValid() || !validMode(sp.startMode)) {
        *errorMessage = QLatin1String("Internal error: Invalid start parameters passed for thre CDB engine.");
337 338
        return 0;
    }
339
    return new CdbEngine(sp, masterEngine, op->options());
340
#else
341
    Q_UNUSED(masterEngine)
342 343
    Q_UNUSED(sp)
#endif
344
    *errorMessage = QString::fromLatin1("Unsupported debug mode");
345 346 347 348 349 350
    return 0;
}

bool isCdbEngineEnabled()
{
#ifdef Q_OS_WIN
351
    return CdbOptionsPage::instance() && CdbOptionsPage::instance()->options()->isValid();
352 353 354 355 356
#else
    return false;
#endif
}

hjk's avatar
hjk committed
357
static inline QString msgNoCdbBinaryForToolChain(const Abi &tc)
358
{
359 360 361
    return CdbEngine::tr("There is no CDB binary available for binaries in format '%1'").arg(tc.toString());
}

hjk's avatar
hjk committed
362
static inline bool isMsvcFlavor(Abi::OSFlavor osf)
363
{
hjk's avatar
hjk committed
364 365
  return osf == Abi::WindowsMsvc2005Flavor
      || osf == Abi::WindowsMsvc2008Flavor
Tobias Hunger's avatar
Tobias Hunger committed
366 367
      || osf == Abi::WindowsMsvc2010Flavor
      || osf == Abi::WindowsMsvc2012Flavor;
368 369
}

370 371 372
bool checkCdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check)
{
#ifdef Q_OS_WIN
Friedemann Kleint's avatar
Friedemann Kleint committed
373
    const Abi abi = sp.toolChainAbi;
374
    if (!isCdbEngineEnabled()) {
375
        check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine required for %1 is currently disabled.").
hjk's avatar
hjk committed
376
                           arg(abi.toString()));
377 378 379
        check->settingsCategory = QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY);
        check->settingsPage = CdbOptionsPage::settingsId();
        return false;
380
    }
381 382

    if (!validMode(sp.startMode)) {
383
        check->errorDetails.push_back(CdbEngine::tr("The CDB engine does not support start mode %1.").arg(sp.startMode));
384 385 386
        return false;
    }

hjk's avatar
hjk committed
387
    if (abi.binaryFormat() != Abi::PEFormat || abi.os() != Abi::WindowsOS) {
388
        check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine does not support the %1 ABI.").
hjk's avatar
hjk committed
389
                                      arg(abi.toString()));
390 391
        return false;
    }
392

hjk's avatar
hjk committed
393
    if (sp.startMode == AttachCore && !isMsvcFlavor(abi.osFlavor())) {
394
        check->errorDetails.push_back(CdbEngine::tr("The CDB debug engine cannot debug gdb core files."));
395 396 397
        return false;
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
398
    if (sp.debuggerCommand.isEmpty()) {
hjk's avatar
hjk committed
399
        check->errorDetails.push_back(msgNoCdbBinaryForToolChain(abi));
Eike Ziller's avatar
Eike Ziller committed
400 401
        check->settingsCategory = QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY);
        check->settingsPage = QLatin1String(ProjectExplorer::Constants::PROJECTEXPLORER_SETTINGS_CATEGORY);
402 403 404
        return false;
    }

405 406 407
    return true;
#else
    Q_UNUSED(sp);
408
    check->errorDetails.push_back(QString::fromLatin1("Unsupported debug mode"));
409 410
    return false;
#endif
411 412
}

413
void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
414
{
415
#ifdef Q_OS_WIN
416
    opts->push_back(new CdbOptionsPage);
417 418 419
#else
    Q_UNUSED(opts);
#endif
420 421 422 423 424 425
}

#define QT_CREATOR_CDB_EXT "qtcreatorcdbext"

static inline Utils::SavedAction *theAssemblerAction()
{
426
    return debuggerCore()->action(OperateByInstruction);
427 428
}

429 430
CdbEngine::CdbEngine(const DebuggerStartParameters &sp,
        DebuggerEngine *masterEngine, const OptionsPtr &options) :
431
    DebuggerEngine(sp, CppLanguage, masterEngine),
432 433 434
    m_creatorExtPrefix("<qtcreatorcdbext>|"),
    m_tokenPrefix("<token>"),
    m_options(options),
435
    m_effectiveStartMode(NoStartMode),
436 437 438 439
    m_accessible(false),
    m_specialStopMode(NoSpecialStop),
    m_nextCommandToken(0),
    m_currentBuiltinCommandIndex(-1),
hjk's avatar
hjk committed
440
    m_extensionCommandPrefixBA("!" QT_CREATOR_CDB_EXT "."),
441 442 443 444
    m_operateByInstructionPending(true),
    m_operateByInstruction(true), // Default CDB setting
    m_notifyEngineShutdownOnTermination(false),
    m_hasDebuggee(false),
445
    m_elapsedLogTime(0),
446
    m_sourceStepInto(false),
447
    m_watchPointX(0),
448 449
    m_watchPointY(0),
    m_ignoreCdbOutput(false)
450
{
451
    connect(theAssemblerAction(), SIGNAL(triggered(bool)), this, SLOT(operateByInstructionTriggered(bool)));
452 453 454 455 456 457 458 459

    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()));
}

460 461 462
void CdbEngine::init()
{
    m_effectiveStartMode = NoStartMode;
463
    notifyInferiorPid(0);
464 465 466 467
    m_accessible = false;
    m_specialStopMode = NoSpecialStop;
    m_nextCommandToken  = 0;
    m_currentBuiltinCommandIndex = -1;
468
    m_operateByInstructionPending = theAssemblerAction()->isChecked();
469 470 471 472 473 474 475 476 477 478 479 480
    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();
481
    m_customSpecialStopData.clear();
482
    m_symbolAddressCache.clear();
483
    m_coreStopReason.reset();
484 485 486 487 488 489 490 491 492 493 494 495 496

    // Create local list of mappings in native separators
    m_sourcePathMappings.clear();
    const QSharedPointer<GlobalDebuggerOptions> globalOptions = debuggerCore()->globalDebuggerOptions();
    if (!globalOptions->sourcePathMap.isEmpty()) {
        typedef GlobalDebuggerOptions::SourcePathMap::const_iterator SourcePathMapIterator;
        m_sourcePathMappings.reserve(globalOptions->sourcePathMap.size());
        const SourcePathMapIterator cend = globalOptions->sourcePathMap.constEnd();
        for (SourcePathMapIterator it = globalOptions->sourcePathMap.constBegin(); it != cend; ++it) {
            m_sourcePathMappings.push_back(SourcePathMapping(QDir::toNativeSeparators(it.key()),
                                                             QDir::toNativeSeparators(it.value())));
        }
    }
497
    QTC_ASSERT(m_process.state() != QProcess::Running, Utils::SynchronousProcess::stopProcess(m_process));
498 499
}

500 501 502 503 504 505
CdbEngine::~CdbEngine()
{
}

void CdbEngine::operateByInstructionTriggered(bool operateByInstruction)
{
506 507 508
    // To be set next time session becomes accessible
    m_operateByInstructionPending = operateByInstruction;
    if (state() == InferiorStopOk)
509 510 511 512 513
        syncOperateByInstruction(operateByInstruction);
}

void CdbEngine::syncOperateByInstruction(bool operateByInstruction)
{
514 515
    if (debug)
        qDebug("syncOperateByInstruction current: %d new %d", m_operateByInstruction, operateByInstruction);
516 517
    if (m_operateByInstruction == operateByInstruction)
        return;
518
    QTC_ASSERT(m_accessible, return);
519 520 521
    m_operateByInstruction = operateByInstruction;
    postCommand(m_operateByInstruction ? QByteArray("l-t") : QByteArray("l+t"), 0);
    postCommand(m_operateByInstruction ? QByteArray("l-s") : QByteArray("l+s"), 0);
522 523
}

524
bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
525 526
                                     TextEditor::ITextEditor *editor,
                                     const DebuggerToolTipContext &contextIn)
527
{
528 529 530 531
    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)
532
        return false;
533 534 535
    // Determine expression and function
    int line;
    int column;
536
    DebuggerToolTipContext context = contextIn;
537
    QString exp = cppExpressionAt(editor, context.position, &line, &column, &context.function);
538
    // Are we in the current stack frame
539
    if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function)
540
        return false;
541 542
    // No numerical or any other expressions [yet]
    if (!(exp.at(0).isLetter() || exp.at(0) == QLatin1Char('_')))
543
        return false;
544 545 546
    // Can this be found as a local variable?
    const QByteArray localsPrefix(localsPrefixC);
    QByteArray iname = localsPrefix + exp.toAscii();
hjk's avatar
hjk committed
547
    if (!watchHandler()->hasItem(iname)) {
548 549 550
        // Nope, try a 'local.this.m_foo'.
        exp.prepend(QLatin1String("this."));
        iname.insert(localsPrefix.size(), "this.");
hjk's avatar
hjk committed
551
        if (!watchHandler()->hasItem(iname))
552 553
            return false;
    }
554
    DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
555
    tw->setContext(context);
hjk's avatar
hjk committed
556
    tw->setDebuggerModel(LocalsType);
557 558
    tw->setExpression(exp);
    tw->acquireEngine(this);
559
    DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw);
560
    return true;
561 562 563
}

// Determine full path to the CDB extension library.
564
QString CdbEngine::extensionLibraryName(bool is64Bit)
565 566 567 568
{
    // Determine extension lib name and path to use
    QString rc;
    QTextStream(&rc) << QFileInfo(QCoreApplication::applicationDirPath()).path()
hjk's avatar
hjk committed
569
                     << "/lib/" << (is64Bit ? QT_CREATOR_CDB_EXT "64" : QT_CREATOR_CDB_EXT "32")
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
                     << '/' << 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;
}

611 612 613 614 615 616 617
// 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);
618 619
    connect(m_consoleStub.data(), SIGNAL(processError(QString)),
            SLOT(consoleStubError(QString)));
620 621 622 623 624
    connect(m_consoleStub.data(), SIGNAL(processStarted()),
            SLOT(consoleStubProcessStarted()));
    connect(m_consoleStub.data(), SIGNAL(wrapperStopped()),
            SLOT(consoleStubExited()));
    m_consoleStub->setWorkingDirectory(sp.workingDirectory);
625 626
    if (sp.environment.size())
        m_consoleStub->setEnvironment(sp.environment);
627 628 629 630 631 632 633
    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;
}

634
void CdbEngine::consoleStubError(const QString &msg)
635
{
636
    if (debug)
637 638 639 640
        qDebug("consoleStubProcessMessage() in %s %s", stateName(state()), qPrintable(msg));
    if (state() == EngineSetupRequested) {
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
        notifyEngineSetupFailed();
641
    } else {
642 643
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
        notifyEngineIll();
644
    }
645
    nonModalMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg);
646 647 648 649 650 651 652 653 654 655 656 657
}

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;
658
    attachParameters.useTerminal = false;
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
    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)))
hjk's avatar
hjk committed
679
        m_options->toSettings(Core::ICore::settings());
680

681 682 683
    init();
    if (!m_logTime.elapsed())
        m_logTime.start();
684 685 686 687 688 689
    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();
690
    const bool launchConsole = isCreatorConsole(sp, *m_options);
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
    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);
708
    const QChar blank(QLatin1Char(' '));
709
    // Start engine which will run until initial breakpoint:
710
    // Determine binary (force MSVC), extension lib name and path to use
711 712
    // The extension is passed as relative name with the path variable set
    //(does not work with absolute path names)
hjk's avatar
hjk committed
713
    const QString executable = sp.debuggerCommand;
714 715 716 717 718 719 720 721 722 723 724 725
    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));
726 727 728 729 730
    if (!extensionFi.isFile()) {
        *errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found.").
                arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
        return false;
    }
731
    const QString extensionFileName = extensionFi.fileName();
732 733
    // Prepare arguments
    QStringList arguments;
734
    const bool isRemote = sp.startMode == AttachToRemoteServer;
735 736 737 738 739
    if (isRemote) { // Must be first
        arguments << QLatin1String("-remote") << sp.remoteChannel;
    } else {
        arguments << (QLatin1String("-a") + extensionFileName);
    }
740 741 742 743
    // Source line info/No terminal breakpoint / Pull extension
    arguments << QLatin1String("-lines") << QLatin1String("-G")
    // register idle (debuggee stop) notification
              << QLatin1String("-c")
744
              << QLatin1String(".idle_cmd ") + QString::fromLatin1(m_extensionCommandPrefixBA) + QLatin1String("idle");
745 746 747 748 749 750
    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(';')));
751 752
    // Compile argument string preserving quotes
    QString nativeArguments = m_options->additionalArguments;
753 754 755
    switch (sp.startMode) {
    case StartInternal:
    case StartExternal:
756 757 758
        if (!nativeArguments.isEmpty())
            nativeArguments.push_back(blank);
        nativeArguments += QDir::toNativeSeparators(sp.executable);
759
        break;
760
    case AttachToRemoteServer:
761
        break;
762
    case AttachExternal:
763
    case AttachCrashedExternal:
764
        arguments << QLatin1String("-p") << QString::number(sp.attachPID);
765
        if (sp.startMode == AttachCrashedExternal) {
766
            arguments << QLatin1String("-e") << sp.crashParameter << QLatin1String("-g");
767
        } else {
768
            if (isCreatorConsole(startParameters(), *m_options))
769 770
                arguments << QLatin1String("-pr") << QLatin1String("-pb");
        }
771
        break;
772 773 774
    case AttachCore:
        arguments << QLatin1String("-z") << sp.coreFile;
        break;
775 776 777 778
    default:
        *errorMessage = QString::fromLatin1("Internal error: Unsupported start mode %1.").arg(sp.startMode);
        return false;
    }
779 780 781 782 783 784
    if (!sp.processArgs.isEmpty()) { // Complete native argument string.
        if (!nativeArguments.isEmpty())
            nativeArguments.push_back(blank);
        nativeArguments += sp.processArgs;
    }

785 786
    const QString msg = QString::fromLatin1("Launching %1 %2\nusing %3 of %4.").
            arg(QDir::toNativeSeparators(executable),
787
                arguments.join(QString(blank)) + blank + nativeArguments,
788 789 790 791 792
                QDir::toNativeSeparators(extensionFi.absoluteFilePath()),
                extensionFi.lastModified().toString(Qt::SystemLocaleShortDate));
    showMessage(msg, LogMisc);

    m_outputBuffer.clear();
793 794 795 796
    const QStringList environment = sp.environment.size() == 0 ?
                                    QProcessEnvironment::systemEnvironment().toStringList() :
                                    sp.environment.toStringList();
    m_process.setEnvironment(mergeEnvironment(environment, extensionFi.absolutePath()));
797 798
    if (!sp.workingDirectory.isEmpty())
        m_process.setWorkingDirectory(sp.workingDirectory);
799

800
#ifdef Q_OS_WIN
801 802
    if (!nativeArguments.isEmpty()) // Appends
        m_process.setNativeArguments(nativeArguments);
803
#endif
804 805 806 807 808 809 810 811 812 813 814 815 816 817
    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;
818 819 820 821 822
    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);
823
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupOk")
824 825
        notifyEngineSetupOk();
    }
826 827 828 829 830
    return true;
}

void CdbEngine::setupInferior()
{
831 832
    if (debug)
        qDebug("setupInferior");
833 834 835 836 837 838
    // QmlCppEngine expects the QML engine to be connected before any breakpoints are hit
    // (attemptBreakpointSynchronization() will be directly called then)
    attemptBreakpointSynchronization();
    if (startParameters().breakOnMain) {
        const BreakpointParameters bp(BreakpointAtMain);
        postCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings,
839
                                            BreakpointModelId(quint16(-1)), true), 0);
840
    }
841
    postCommand("sxn 0x4000001f", 0); // Do not break on WowX86 exceptions.
842
    postCommand(".asm source_line", 0); // Source line in assembly
843 844 845 846 847
    postExtensionCommand("pid", QByteArray(), 0, &CdbEngine::handlePid);
}

void CdbEngine::runEngine()
{
848 849
    if (debug)
        qDebug("runEngine");
850 851
    foreach (const QString &breakEvent, m_options->breakEvents)
            postCommand(QByteArray("sxe ") + breakEvent.toAscii(), 0);
852 853 854 855 856 857 858
    if (startParameters().startMode == AttachCore) {
        QTC_ASSERT(!m_coreStopReason.isNull(), return; );
        notifyInferiorUnrunnable();
        processStop(*m_coreStopReason, false);
    } else {
        postCommand("g", 0);
    }
859 860
}

861 862 863 864 865
bool CdbEngine::commandsPending() const
{
    return !m_builtinCommandQueue.isEmpty() || !m_extensionCommandQueue.isEmpty();
}

866 867 868 869 870 871 872 873 874
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");
875
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
876 877 878
        notifyInferiorShutdownOk();
        return;
    }
879

880 881
    if (m_accessible) { // except console.
        if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
882
            detachDebugger();
883
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorShutdownOk")
884 885
        notifyInferiorShutdownOk();
    } else {
886 887 888 889 890 891 892 893 894 895 896 897 898
        // 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;
        }
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
        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)
914 915 916 917
        qDebug("CdbEngine::shutdownEngine in state '%s', process running %d,"
               "accessible=%d,commands pending=%d",
               stateName(state()), isCdbProcessRunning(), m_accessible,
               commandsPending());
918 919

    if (!isCdbProcessRunning()) { // Direct launch: Terminated with process.
920
        STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
921 922 923 924
        notifyEngineShutdownOk();
        return;
    }

925
    // No longer trigger anything from messages
926
    m_ignoreCdbOutput = true;
927 928
    // Go for kill if there are commands pending.
    if (m_accessible && !commandsPending()) {
929 930
        // detach (except console): Wait for debugger to finish.
        if (startParameters().startMode == AttachExternal || startParameters().startMode == AttachCrashedExternal)
931
            detachDebugger();
932
        // Remote requires a bit more force to quit.
933
        if (m_effectiveStartMode == AttachToRemoteServer) {
934 935 936 937 938 939 940 941 942
            postCommand(m_extensionCommandPrefixBA + "shutdownex", 0);
            postCommand("qq", 0);
        } else {
            postCommand("q", 0);
        }
        m_notifyEngineShutdownOnTermination = true;
        return;
    } else {
        // Remote process. No can do, currently
943
        m_notifyEngineShutdownOnTermination = true;
944
        Utils::SynchronousProcess::stopProcess(m_process);
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
        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");
973
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineIll")
974 975
            notifyEngineIll();
        } else {
976
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineShutdownOk")
977 978 979
            notifyEngineShutdownOk();
        }
    } else {
980 981 982 983 984 985 986 987 988
        // The QML/CPP engine relies on the standard sequence of InferiorShutDown,etc.
        // Otherwise, we take a shortcut.
        if (isSlaveEngine()) {
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorExited")
            notifyInferiorExited();
        } else {
            STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSpontaneousShutdown")
            notifyEngineSpontaneousShutdown();
        }
989 990 991 992 993 994 995 996
    }
}

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

997 998 999 1000 1001
static inline bool isWatchIName(const QByteArray &iname)
{
    return iname.startsWith("watch");
}

1002 1003
void CdbEngine::updateWatchData(const WatchData &dataIn,
                                const WatchUpdateFlags & flags)
1004
{
1005 1006 1007
    if (debug || debugLocals || debugWatches)
        qDebug("CdbEngine::updateWatchData() %dms accessible=%d %s incr=%d: %s",
               elapsedLogTime(), m_accessible, stateName(state()),
1008 1009 1010
               flags.tryIncremental,
               qPrintable(dataIn.toString()));

1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
    if (!m_accessible) // Add watch data while running?