<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (<EMAIL>)
**
**
** GNU Lesser General Public License Usage
**
** 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.
**
** 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.
**
** 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at <EMAIL>.
**
**************************************************************************/

#include "debuggerrunner.h"
#include "debuggerruncontrolfactory.h"

#include "debuggeractions.h"
#include "debuggerinternalconstants.h"
#include "debuggercore.h"
#include "debuggerengine.h"
#include "debuggermainwindow.h"
#include "debuggerplugin.h"
#include "debuggerstringutils.h"
#include "debuggerstartparameters.h"
#include "lldb/lldbenginehost.h"
#include "debuggertooltipmanager.h"
#include "qml/qmlengine.h"

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

#include <projectexplorer/abi.h>
#include <projectexplorer/debugginghelper.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/applicationrunconfiguration.h> // For LocalApplication*

#include <utils/outputformat.h>
#include <utils/synchronousprocess.h>
#include <utils/qtcassert.h>
#include <utils/fancymainwindow.h>
#include <utils/qtcprocess.h>
#include <coreplugin/icore.h>
#include <utils/buildablehelperlibrary.h>

#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <QtGui/QMessageBox>
#include <QtGui/QErrorMessage>

using namespace ProjectExplorer;
using namespace Debugger::Internal;

enum { debug = 0 };

namespace Debugger {
namespace Internal {

bool isCdbEngineEnabled(); // Check the configuration page
bool checkCdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check);
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp,
    DebuggerEngine *masterEngine, QString *error);

bool checkGdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check);
DebuggerEngine *createGdbEngine(const DebuggerStartParameters &sp,
    DebuggerEngine *masterEngine);

DebuggerEngine *createScriptEngine(const DebuggerStartParameters &sp);
DebuggerEngine *createPdbEngine(const DebuggerStartParameters &sp);
QmlEngine *createQmlEngine(const DebuggerStartParameters &sp,
    DebuggerEngine *masterEngine);
DebuggerEngine *createQmlCppEngine(const DebuggerStartParameters &sp,
                                   DebuggerEngineType slaveEngineType,
                                   QString *errorMessage);
DebuggerEngine *createLldbEngine(const DebuggerStartParameters &sp);

extern QString msgNoBinaryForToolChain(const Abi &abi);

static const char *engineTypeName(DebuggerEngineType et)
{
    switch (et) {
    case Debugger::NoEngineType:
        break;
    case Debugger::GdbEngineType:
        return "Gdb engine";
    case Debugger::ScriptEngineType:
        return "Script engine";
    case Debugger::CdbEngineType:
        return "Cdb engine";
    case Debugger::PdbEngineType:
        return "Pdb engine";
    case Debugger::QmlEngineType:
        return "QML engine";
    case Debugger::QmlCppEngineType:
        return "QML C++ engine";
    case Debugger::LldbEngineType:
        return "LLDB engine";
    case Debugger::AllEngineTypes:
        break;
    }
    return "No engine";
}

static inline QString engineTypeNames(const QList<DebuggerEngineType> &l)
{
    QString rc;
    foreach (DebuggerEngineType et, l) {
        if (!rc.isEmpty())
            rc.append(QLatin1String(", "));
        rc += QLatin1String(engineTypeName(et));
    }
    return rc;
}

static QString msgEngineNotAvailable(const char *engine)
{
    return DebuggerPlugin::tr("The application requires the debugger engine '%1', "
        "which is disabled.").arg(_(engine));
}

static inline QString msgEngineNotAvailable(DebuggerEngineType et)
{
    return msgEngineNotAvailable(engineTypeName(et));
}

////////////////////////////////////////////////////////////////////////
//
// DebuggerRunControlPrivate
//
////////////////////////////////////////////////////////////////////////

class DebuggerRunControlPrivate
{
public:
    explicit DebuggerRunControlPrivate(DebuggerRunControl *parent,
                                       RunConfiguration *runConfiguration);

    DebuggerEngineType engineForExecutable(unsigned enabledEngineTypes,
        const QString &executable);
    DebuggerEngineType engineForMode(unsigned enabledEngineTypes,
        DebuggerStartMode mode);

public:
    DebuggerRunControl *q;
    DebuggerEngine *m_engine;
    const QWeakPointer<RunConfiguration> m_myRunConfiguration;
    bool m_running;
};

DebuggerRunControlPrivate::DebuggerRunControlPrivate(DebuggerRunControl *parent,
                                                     RunConfiguration *runConfiguration)
    : q(parent)
    , m_engine(0)
    , m_myRunConfiguration(runConfiguration)
    , m_running(false)
{
}

} // namespace Internal

DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration,
                                       const DebuggerStartParameters &sp,
                                       const QPair<DebuggerEngineType, DebuggerEngineType> &masterSlaveEngineTypes)
    : RunControl(runConfiguration, Constants::DEBUGMODE),
      d(new DebuggerRunControlPrivate(this, runConfiguration))
{
    connect(this, SIGNAL(finished()), SLOT(handleFinished()));
    // Create the engine. Could arguably be moved to the factory, but
    // we still have a derived S60DebugControl. Should rarely fail, though.
    QString errorMessage;
    d->m_engine = masterSlaveEngineTypes.first == QmlCppEngineType ?
            createQmlCppEngine(sp, masterSlaveEngineTypes.second, &errorMessage) :
            DebuggerRunControlFactory::createEngine(masterSlaveEngineTypes.first, sp,
                                                    0, &errorMessage);
    if (d->m_engine) {
        DebuggerToolTipManager::instance()->registerEngine(d->m_engine);
    } else {
        debuggingFinished();
        Core::ICore::instance()->showWarningWithOptions(DebuggerRunControl::tr("Debugger"), errorMessage);
    }
}

DebuggerRunControl::~DebuggerRunControl()
{
    disconnect();
    if (DebuggerEngine *engine = d->m_engine) {
        d->m_engine = 0;
        engine->disconnect();
        delete engine;
    }
    delete d;
}

const DebuggerStartParameters &DebuggerRunControl::startParameters() const
{
    QTC_ASSERT(d->m_engine, return *(new DebuggerStartParameters()));
    return d->m_engine->startParameters();
}

QString DebuggerRunControl::displayName() const
{
    QTC_ASSERT(d->m_engine, return QString());
    return d->m_engine->startParameters().displayName;
}

QIcon DebuggerRunControl::icon() const
{
    return QIcon(ProjectExplorer::Constants::ICON_DEBUG_SMALL);
}

void DebuggerRunControl::setCustomEnvironment(Utils::Environment env)
{
    QTC_ASSERT(d->m_engine, return);
    d->m_engine->startParameters().environment = env;
}

void DebuggerRunControl::start()
{
    QTC_ASSERT(d->m_engine, return);
    // User canceled input dialog asking for executable when working on library project.
    if (d->m_engine->startParameters().startMode == StartInternal
        && d->m_engine->startParameters().executable.isEmpty()) {
        appendMessage(tr("No executable specified.\n"), Utils::ErrorMessageFormat);
        emit started();
        emit finished();
        return;
    }

    if (d->m_engine->startParameters().startMode == StartInternal) {
        foreach (const BreakpointModelId &id, debuggerCore()->breakHandler()->allBreakpointIds()) {
            if (d->m_engine->breakHandler()->breakpointData(id).enabled
                    && !d->m_engine->acceptsBreakpoint(id)) {

                QString warningMessage =
                        DebuggerPlugin::tr("Some breakpoints cannot be handled by the debugger "
                                           "languages currently active, and will be ignored.");

                debuggerCore()->showMessage(warningMessage, LogWarning);

                QErrorMessage *msgBox = new QErrorMessage(debuggerCore()->mainWindow());
                msgBox->setAttribute(Qt::WA_DeleteOnClose);
                msgBox->showMessage(warningMessage);
                break;
            }
        }
    }

    debuggerCore()->runControlStarted(d->m_engine);

    // We might get a synchronous startFailed() notification on Windows,
    // when launching the process fails. Emit a proper finished() sequence.
    emit started();
    d->m_running = true;

    d->m_engine->startDebugger(this);

    if (d->m_running)
        appendMessage(tr("Debugging starts\n"), Utils::NormalMessageFormat);
}

void DebuggerRunControl::startFailed()
{
    appendMessage(tr("Debugging has failed\n"), Utils::NormalMessageFormat);
    d->m_running = false;
    emit finished();
    d->m_engine->handleStartFailed();
}

void DebuggerRunControl::handleFinished()
{
    appendMessage(tr("Debugging has finished\n"), Utils::NormalMessageFormat);
    if (d->m_engine)
        d->m_engine->handleFinished();
    debuggerCore()->runControlFinished(d->m_engine);
}

void DebuggerRunControl::showMessage(const QString &msg, int channel)
{
    switch (channel) {
        case AppOutput:
            appendMessage(msg, Utils::StdOutFormatSameLine);
            break;
        case AppError:
            appendMessage(msg, Utils::StdErrFormatSameLine);
            break;
        case AppStuff:
            appendMessage(msg, Utils::DebugFormat);
            break;
    }
}

bool DebuggerRunControl::promptToStop(bool *optionalPrompt) const
{
    QTC_ASSERT(isRunning(), return true;)

    if (optionalPrompt && !*optionalPrompt)
        return true;

    const QString question = tr("A debugging session is still in progress. "
            "Terminating the session in the current"
            " state can leave the target in an inconsistent state."
            " Would you still like to terminate it?");
    return showPromptToStopDialog(tr("Close Debugging Session"), question,
                                  QString(), QString(), optionalPrompt);
}

RunControl::StopResult DebuggerRunControl::stop()
{
    QTC_ASSERT(d->m_engine, return StoppedSynchronously);
    d->m_engine->quitDebugger();
    return AsynchronousStop;
}

void DebuggerRunControl::debuggingFinished()
{
    d->m_running = false;
    emit finished();
}

bool DebuggerRunControl::isRunning() const
{
    return d->m_running;
}

DebuggerEngine *DebuggerRunControl::engine()
{
    QTC_CHECK(d->m_engine);
    return d->m_engine;
}

RunConfiguration *DebuggerRunControl::runConfiguration() const
{
    return d->m_myRunConfiguration.data();
}

////////////////////////////////////////////////////////////////////////
//
// Engine detection logic: Detection functions depending on tool chain, binary,
// etc. Return a list of possible engines (order of prefererence) without
// consideration of configuration, etc.
//
////////////////////////////////////////////////////////////////////////

static QList<DebuggerEngineType> enginesForToolChain(const Abi &toolChain)
{
    QList<DebuggerEngineType> result;
    switch (toolChain.binaryFormat()) {
    case Abi::ElfFormat:
    case Abi::MachOFormat:
        result.push_back(LldbEngineType);
        result.push_back(GdbEngineType);
        break;
   case Abi::PEFormat:
        if (toolChain.osFlavor() == Abi::WindowsMSysFlavor) {
            result.push_back(GdbEngineType);
            result.push_back(CdbEngineType);
        } else {
            result.push_back(CdbEngineType);
            result.push_back(GdbEngineType);
        }
        break;
    case Abi::RuntimeQmlFormat:
        result.push_back(QmlEngineType);
        break;
    default:
        break;
    }
    return result;
}

static inline QList<DebuggerEngineType> enginesForScriptExecutables(const QString &executable)
{
    QList<DebuggerEngineType> result;
    if (executable.endsWith(_(".js"))) {
        result.push_back(ScriptEngineType);
    } else if (executable.endsWith(_(".py"))) {
        result.push_back(PdbEngineType);
    }
    return result;
}

static QList<DebuggerEngineType> enginesForExecutable(const QString &executable)
{
    QList<DebuggerEngineType> result = enginesForScriptExecutables(executable);
    if (!result.isEmpty())
        return result;
#ifdef Q_OS_WIN
    // A remote executable?
    if (!executable.endsWith(_(".exe"), Qt::CaseInsensitive)) {
        result.push_back(GdbEngineType);
        return result;
    }

    // If a file has PDB files, it has been compiled by VS.
    QStringList pdbFiles;
    QString errorMessage;
    if (getPDBFiles(executable, &pdbFiles, &errorMessage) && !pdbFiles.isEmpty()) {
        result.push_back(CdbEngineType);
        result.push_back(GdbEngineType);
        return result;
    }
    // Fixme: Gdb should only be preferred if MinGW can positively be detected.
    result.push_back(GdbEngineType);
    result.push_back(CdbEngineType);
#else
    result.push_back(LldbEngineType);
    result.push_back(GdbEngineType);
#endif
    return result;
}

// Debugger type for mode.
static QList<DebuggerEngineType> enginesForMode(DebuggerStartMode startMode,
                                                bool hardConstraintsOnly)
{
    QList<DebuggerEngineType> result;
    switch (startMode) {
    case NoStartMode:
        break;
    case StartInternal:
    case StartExternal:
    case AttachExternal:
        if (!hardConstraintsOnly) {
#ifdef Q_OS_WIN
            result.push_back(CdbEngineType); // Preferably Windows debugger for attaching locally.
#endif
            result.push_back(GdbEngineType);
        }
        break;
    case AttachCore:
#ifdef Q_OS_WIN
        result.push_back(CdbEngineType);
#endif
        result.push_back(GdbEngineType);
        break;
    case StartRemoteGdb:
        result.push_back(GdbEngineType);
        break;
    case AttachToRemoteServer:
        if (!hardConstraintsOnly) {
#ifdef Q_OS_WIN
            result.push_back(CdbEngineType);
#endif
            result.push_back(GdbEngineType);<commit_msg>debugger: fix compiler warning for not-yet-used enumeration value<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (<EMAIL>)
**
**
** GNU Lesser General Public License Usage
**
** 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.
**
** 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.
**
** 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at <EMAIL>.
**
**************************************************************************/

#include "debuggerrunner.h"
#include "debuggerruncontrolfactory.h"

#include "debuggeractions.h"
#include "debuggerinternalconstants.h"
#include "debuggercore.h"
#include "debuggerengine.h"
#include "debuggermainwindow.h"
#include "debuggerplugin.h"
#include "debuggerstringutils.h"
#include "debuggerstartparameters.h"
#include "lldb/lldbenginehost.h"
#include "debuggertooltipmanager.h"
#include "qml/qmlengine.h"

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

#include <projectexplorer/abi.h>
#include <projectexplorer/debugginghelper.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/applicationrunconfiguration.h> // For LocalApplication*

#include <utils/outputformat.h>
#include <utils/synchronousprocess.h>
#include <utils/qtcassert.h>
#include <utils/fancymainwindow.h>
#include <utils/qtcprocess.h>
#include <coreplugin/icore.h>
#include <utils/buildablehelperlibrary.h>

#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <QtGui/QMessageBox>
#include <QtGui/QErrorMessage>

using namespace ProjectExplorer;
using namespace Debugger::Internal;

enum { debug = 0 };

namespace Debugger {
namespace Internal {

bool isCdbEngineEnabled(); // Check the configuration page
bool checkCdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check);
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp,
    DebuggerEngine *masterEngine, QString *error);

bool checkGdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check);
DebuggerEngine *createGdbEngine(const DebuggerStartParameters &sp,
    DebuggerEngine *masterEngine);

DebuggerEngine *createScriptEngine(const DebuggerStartParameters &sp);
DebuggerEngine *createPdbEngine(const DebuggerStartParameters &sp);
QmlEngine *createQmlEngine(const DebuggerStartParameters &sp,
    DebuggerEngine *masterEngine);
DebuggerEngine *createQmlCppEngine(const DebuggerStartParameters &sp,
                                   DebuggerEngineType slaveEngineType,
                                   QString *errorMessage);
DebuggerEngine *createLldbEngine(const DebuggerStartParameters &sp);

extern QString msgNoBinaryForToolChain(const Abi &abi);

static const char *engineTypeName(DebuggerEngineType et)
{
    switch (et) {
    case Debugger::NoEngineType:
        break;
    case Debugger::GdbEngineType:
        return "Gdb engine";
    case Debugger::ScriptEngineType:
        return "Script engine";
    case Debugger::CdbEngineType:
        return "Cdb engine";
    case Debugger::PdbEngineType:
        return "Pdb engine";
    case Debugger::QmlEngineType:
        return "QML engine";
    case Debugger::QmlCppEngineType:
        return "QML C++ engine";
    case Debugger::LldbEngineType:
        return "LLDB engine";
    case Debugger::AllEngineTypes:
        break;
    }
    return "No engine";
}

static inline QString engineTypeNames(const QList<DebuggerEngineType> &l)
{
    QString rc;
    foreach (DebuggerEngineType et, l) {
        if (!rc.isEmpty())
            rc.append(QLatin1String(", "));
        rc += QLatin1String(engineTypeName(et));
    }
    return rc;
}

static QString msgEngineNotAvailable(const char *engine)
{
    return DebuggerPlugin::tr("The application requires the debugger engine '%1', "
        "which is disabled.").arg(_(engine));
}

static inline QString msgEngineNotAvailable(DebuggerEngineType et)
{
    return msgEngineNotAvailable(engineTypeName(et));
}

////////////////////////////////////////////////////////////////////////
//
// DebuggerRunControlPrivate
//
////////////////////////////////////////////////////////////////////////

class DebuggerRunControlPrivate
{
public:
    explicit DebuggerRunControlPrivate(DebuggerRunControl *parent,
                                       RunConfiguration *runConfiguration);

    DebuggerEngineType engineForExecutable(unsigned enabledEngineTypes,
        const QString &executable);
    DebuggerEngineType engineForMode(unsigned enabledEngineTypes,
        DebuggerStartMode mode);

public:
    DebuggerRunControl *q;
    DebuggerEngine *m_engine;
    const QWeakPointer<RunConfiguration> m_myRunConfiguration;
    bool m_running;
};

DebuggerRunControlPrivate::DebuggerRunControlPrivate(DebuggerRunControl *parent,
                                                     RunConfiguration *runConfiguration)
    : q(parent)
    , m_engine(0)
    , m_myRunConfiguration(runConfiguration)
    , m_running(false)
{
}

} // namespace Internal

DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration,
                                       const DebuggerStartParameters &sp,
                                       const QPair<DebuggerEngineType, DebuggerEngineType> &masterSlaveEngineTypes)
    : RunControl(runConfiguration, Constants::DEBUGMODE),
      d(new DebuggerRunControlPrivate(this, runConfiguration))
{
    connect(this, SIGNAL(finished()), SLOT(handleFinished()));
    // Create the engine. Could arguably be moved to the factory, but
    // we still have a derived S60DebugControl. Should rarely fail, though.
    QString errorMessage;
    d->m_engine = masterSlaveEngineTypes.first == QmlCppEngineType ?
            createQmlCppEngine(sp, masterSlaveEngineTypes.second, &errorMessage) :
            DebuggerRunControlFactory::createEngine(masterSlaveEngineTypes.first, sp,
                                                    0, &errorMessage);
    if (d->m_engine) {
        DebuggerToolTipManager::instance()->registerEngine(d->m_engine);
    } else {
        debuggingFinished();
        Core::ICore::instance()->showWarningWithOptions(DebuggerRunControl::tr("Debugger"), errorMessage);
    }
}

DebuggerRunControl::~DebuggerRunControl()
{
    disconnect();
    if (DebuggerEngine *engine = d->m_engine) {
        d->m_engine = 0;
        engine->disconnect();
        delete engine;
    }
    delete d;
}

const DebuggerStartParameters &DebuggerRunControl::startParameters() const
{
    QTC_ASSERT(d->m_engine, return *(new DebuggerStartParameters()));
    return d->m_engine->startParameters();
}

QString DebuggerRunControl::displayName() const
{
    QTC_ASSERT(d->m_engine, return QString());
    return d->m_engine->startParameters().displayName;
}

QIcon DebuggerRunControl::icon() const
{
    return QIcon(ProjectExplorer::Constants::ICON_DEBUG_SMALL);
}

void DebuggerRunControl::setCustomEnvironment(Utils::Environment env)
{
    QTC_ASSERT(d->m_engine, return);
    d->m_engine->startParameters().environment = env;
}

void DebuggerRunControl::start()
{
    QTC_ASSERT(d->m_engine, return);
    // User canceled input dialog asking for executable when working on library project.
    if (d->m_engine->startParameters().startMode == StartInternal
        && d->m_engine->startParameters().executable.isEmpty()) {
        appendMessage(tr("No executable specified.\n"), Utils::ErrorMessageFormat);
        emit started();
        emit finished();
        return;
    }

    if (d->m_engine->startParameters().startMode == StartInternal) {
        foreach (const BreakpointModelId &id, debuggerCore()->breakHandler()->allBreakpointIds()) {
            if (d->m_engine->breakHandler()->breakpointData(id).enabled
                    && !d->m_engine->acceptsBreakpoint(id)) {

                QString warningMessage =
                        DebuggerPlugin::tr("Some breakpoints cannot be handled by the debugger "
                                           "languages currently active, and will be ignored.");

                debuggerCore()->showMessage(warningMessage, LogWarning);

                QErrorMessage *msgBox = new QErrorMessage(debuggerCore()->mainWindow());
                msgBox->setAttribute(Qt::WA_DeleteOnClose);
                msgBox->showMessage(warningMessage);
                break;
            }
        }
    }

    debuggerCore()->runControlStarted(d->m_engine);

    // We might get a synchronous startFailed() notification on Windows,
    // when launching the process fails. Emit a proper finished() sequence.
    emit started();
    d->m_running = true;

    d->m_engine->startDebugger(this);

    if (d->m_running)
        appendMessage(tr("Debugging starts\n"), Utils::NormalMessageFormat);
}

void DebuggerRunControl::startFailed()
{
    appendMessage(tr("Debugging has failed\n"), Utils::NormalMessageFormat);
    d->m_running = false;
    emit finished();
    d->m_engine->handleStartFailed();
}

void DebuggerRunControl::handleFinished()
{
    appendMessage(tr("Debugging has finished\n"), Utils::NormalMessageFormat);
    if (d->m_engine)
        d->m_engine->handleFinished();
    debuggerCore()->runControlFinished(d->m_engine);
}

void DebuggerRunControl::showMessage(const QString &msg, int channel)
{
    switch (channel) {
        case AppOutput:
            appendMessage(msg, Utils::StdOutFormatSameLine);
            break;
        case AppError:
            appendMessage(msg, Utils::StdErrFormatSameLine);
            break;
        case AppStuff:
            appendMessage(msg, Utils::DebugFormat);
            break;
    }
}

bool DebuggerRunControl::promptToStop(bool *optionalPrompt) const
{
    QTC_ASSERT(isRunning(), return true;)

    if (optionalPrompt && !*optionalPrompt)
        return true;

    const QString question = tr("A debugging session is still in progress. "
            "Terminating the session in the current"
            " state can leave the target in an inconsistent state."
            " Would you still like to terminate it?");
    return showPromptToStopDialog(tr("Close Debugging Session"), question,
                                  QString(), QString(), optionalPrompt);
}

RunControl::StopResult DebuggerRunControl::stop()
{
    QTC_ASSERT(d->m_engine, return StoppedSynchronously);
    d->m_engine->quitDebugger();
    return AsynchronousStop;
}

void DebuggerRunControl::debuggingFinished()
{
    d->m_running = false;
    emit finished();
}

bool DebuggerRunControl::isRunning() const
{
    return d->m_running;
}

DebuggerEngine *DebuggerRunControl::engine()
{
    QTC_CHECK(d->m_engine);
    return d->m_engine;
}

RunConfiguration *DebuggerRunControl::runConfiguration() const
{
    return d->m_myRunConfiguration.data();
}

////////////////////////////////////////////////////////////////////////
//
// Engine detection logic: Detection functions depending on tool chain, binary,
// etc. Return a list of possible engines (order of prefererence) without
// consideration of configuration, etc.
//
////////////////////////////////////////////////////////////////////////

static QList<DebuggerEngineType> enginesForToolChain(const Abi &toolChain)
{
    QList<DebuggerEngineType> result;
    switch (toolChain.binaryFormat()) {
    case Abi::ElfFormat:
    case Abi::MachOFormat:
        result.push_back(LldbEngineType);
        result.push_back(GdbEngineType);
        break;
   case Abi::PEFormat:
        if (toolChain.osFlavor() == Abi::WindowsMSysFlavor) {
            result.push_back(GdbEngineType);
            result.push_back(CdbEngineType);
        } else {
            result.push_back(CdbEngineType);
            result.push_back(GdbEngineType);
        }
        break;
    case Abi::RuntimeQmlFormat:
        result.push_back(QmlEngineType);
        break;
    default:
        break;
    }
    return result;
}

static inline QList<DebuggerEngineType> enginesForScriptExecutables(const QString &executable)
{
    QList<DebuggerEngineType> result;
    if (executable.endsWith(_(".js"))) {
        result.push_back(ScriptEngineType);
    } else if (executable.endsWith(_(".py"))) {
        result.push_back(PdbEngineType);
    }
    return result;
}

static QList<DebuggerEngineType> enginesForExecutable(const QString &executable)
{
    QList<DebuggerEngineType> result = enginesForScriptExecutables(executable);
    if (!result.isEmpty())
        return result;
#ifdef Q_OS_WIN
    // A remote executable?
    if (!executable.endsWith(_(".exe"), Qt::CaseInsensitive)) {
        result.push_back(GdbEngineType);
        return result;
    }

    // If a file has PDB files, it has been compiled by VS.
    QStringList pdbFiles;
    QString errorMessage;
    if (getPDBFiles(executable, &pdbFiles, &errorMessage) && !pdbFiles.isEmpty()) {
        result.push_back(CdbEngineType);
        result.push_back(GdbEngineType);
        return result;
    }
    // Fixme: Gdb should only be preferred if MinGW can positively be detected.
    result.push_back(GdbEngineType);
    result.push_back(CdbEngineType);
#else
    result.push_back(LldbEngineType);
    result.push_back(GdbEngineType);
#endif
    return result;
}

// Debugger type for mode.
static QList<DebuggerEngineType> enginesForMode(DebuggerStartMode startMode,
                                                bool hardConstraintsOnly)
{
    QList<DebuggerEngineType> result;
    switch (startMode) {
    case NoStartMode:
        break;
    case StartInternal:
    case StartExternal:
    case AttachExternal:
        if (!hardConstraintsOnly) {
#ifdef Q_OS_WIN
            result.push_back(CdbEngineType); // Preferably Windows debugger for attaching locally.
#endif
            result.push_back(GdbEngineType);
        }
        break;
    case AttachCore:
#ifdef Q_OS_WIN
        result.push_back(CdbEngineType);
#endif
        result.push_back(GdbEngineType);
        break;
    case StartRemote:
    case StartRemoteGdb:
        result.push_back(GdbEngineType);
        break;
    case AttachToRemoteServer:
        if (!hardConstraintsOnly) {
#ifdef Q_OS_WIN
            result.push_back(CdbEngineType);
#endif
            result.push_back(GdbEngineType);
{'fraction_non_alphanumeric': 0.12823911458678508, 'fraction_numerical': 0.0013917423288488302, 'mean_word_length': 3.2350547291608196, 'pattern_counts': {'":': 0, '<': 69, '<?xml version=': 0, '>': 183, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 28, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '354510', 'n_tokens_mistral': 8346, 'n_tokens_neox': 8277, 'n_words': 1934}