Commit 3d11a27a authored by hjk's avatar hjk

Debugger: Consolidate "Attach to running process"

Change-Id: I78e89a662140f37f5f9719dbbbff070f1e2fbe84
Reviewed-by: Christian Stenger's avatarChristian Stenger <christian.stenger@qt.io>
parent 6a470f0a
......@@ -110,7 +110,6 @@ Project {
files: [
"gdbengine.cpp", "gdbengine.h",
"gdboptionspage.cpp",
"startgdbserverdialog.cpp", "startgdbserverdialog.h",
]
}
......
......@@ -61,7 +61,6 @@
#include "snapshothandler.h"
#include "threadshandler.h"
#include "commonoptionspage.h"
#include "gdb/startgdbserverdialog.h"
#include "analyzer/analyzerconstants.h"
#include "analyzer/analyzermanager.h"
......@@ -735,7 +734,6 @@ public:
void updateDebugWithoutDeployMenu();
void startRemoteCdbSession();
void startRemoteServerAndAttachToProcess();
void attachToRunningApplication();
void attachToUnstartedApplicationDialog();
void attachToQmlPort();
......@@ -981,7 +979,6 @@ public:
QAction *m_startAction = 0;
QAction *m_debugWithoutDeployAction = 0;
QAction *m_startAndDebugApplicationAction = 0;
QAction *m_startRemoteServerAction = 0;
QAction *m_attachToRunningApplication = 0;
QAction *m_attachToUnstartedApplication = 0;
QAction *m_attachToQmlPortAction = 0;
......@@ -1507,10 +1504,6 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
act->setText(tr("Attach to Running Debug Server..."));
connect(act, &QAction::triggered, this, &StartApplicationDialog::attachToRemoteServer);
act = m_startRemoteServerAction = new QAction(this);
act->setText(tr("Start Debug Server Attached to Process..."));
connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startRemoteServerAndAttachToProcess);
act = m_attachToRunningApplication = new QAction(this);
act->setText(tr("Attach to Running Application..."));
connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRunningApplication);
......@@ -1584,11 +1577,6 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
cmd->setAttribute(Command::CA_Hide);
mstart->addAction(cmd, Constants::G_SPECIAL);
cmd = ActionManager::registerAction(m_startRemoteServerAction,
"Debugger.StartRemoteServer");
cmd->setDescription(tr("Start Gdbserver"));
mstart->addAction(cmd, Constants::G_SPECIAL);
if (m_startRemoteCdbAction) {
cmd = ActionManager::registerAction(m_startRemoteCdbAction,
"Debugger.AttachRemoteCdb");
......@@ -1992,30 +1980,48 @@ void DebuggerPluginPrivate::startRemoteCdbSession()
debugger->startRunControl();
}
void DebuggerPluginPrivate::startRemoteServerAndAttachToProcess()
class RemoteAttachRunner : public DebuggerRunTool
{
auto kitChooser = new DebuggerKitChooser(DebuggerKitChooser::AnyDebugging);
auto dlg = new DeviceProcessesDialog(kitChooser, ICore::dialogParent());
dlg->addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process"));
dlg->showAllDevices();
if (dlg->exec() == QDialog::Rejected) {
delete dlg;
return;
public:
RemoteAttachRunner(RunControl *runControl, Kit *kit, int pid)
: DebuggerRunTool(runControl, kit)
{
IDevice::ConstPtr device = DeviceKitInformation::device(kit);
setDisplayName("AttachToRunningProcess");
portsGatherer = new GdbServerPortsGatherer(runControl);
portsGatherer->setUseGdbServer(true);
portsGatherer->setUseQmlServer(false);
portsGatherer->setDevice(device);
auto gdbServer = new GdbServerRunner(runControl, portsGatherer);
gdbServer->setUseMulti(false);
gdbServer->addStartDependency(portsGatherer);
gdbServer->setDevice(device);
gdbServer->setAttachPid(ProcessHandle(pid));
addStartDependency(gdbServer);
setStartMode(AttachToRemoteProcess);
setCloseMode(DetachAtClose);
// setInferiorExecutable(localExecutable);
setUseContinueInsteadOfRun(true);
setContinueAfterAttach(false);
}
dlg->setAttribute(Qt::WA_DeleteOnClose);
Kit *kit = kitChooser->currentKit();
QTC_ASSERT(kit, return);
IDevice::ConstPtr device = DeviceKitInformation::device(kit);
QTC_ASSERT(device, return);
void start() final
{
setRemoteChannel(portsGatherer->gdbServerChannel());
DebuggerRunTool::start();
}
GdbServerStarter *starter = new GdbServerStarter(dlg, true);
starter->run();
}
GdbServerPortsGatherer *portsGatherer;
};
void DebuggerPluginPrivate::attachToRunningApplication()
{
auto kitChooser = new DebuggerKitChooser(DebuggerKitChooser::LocalDebugging);
auto kitChooser = new DebuggerKitChooser(DebuggerKitChooser::AnyDebugging);
auto dlg = new DeviceProcessesDialog(kitChooser, ICore::dialogParent());
dlg->addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process"));
......@@ -2031,11 +2037,14 @@ void DebuggerPluginPrivate::attachToRunningApplication()
IDevice::ConstPtr device = DeviceKitInformation::device(kit);
QTC_ASSERT(device, return);
DeviceProcessItem process = dlg->currentProcess();
if (device->type() == PE::DESKTOP_DEVICE_TYPE) {
attachToRunningProcess(kit, dlg->currentProcess(), false);
attachToRunningProcess(kit, process, false);
} else {
GdbServerStarter *starter = new GdbServerStarter(dlg, true);
starter->run();
auto runControl = new RunControl(nullptr, ProjectExplorer::Constants::DEBUG_RUN_MODE);
auto debugger = new RemoteAttachRunner(runControl, kit, process.pid);
debugger->startRunControl();
}
}
......
......@@ -936,6 +936,8 @@ GdbServerPortsGatherer::GdbServerPortsGatherer(RunControl *runControl)
this, &RunWorker::reportFailure);
connect(&m_portsGatherer, &DeviceUsedPortsGatherer::portListReady,
this, &GdbServerPortsGatherer::handlePortListReady);
m_device = runControl->device();
}
GdbServerPortsGatherer::~GdbServerPortsGatherer()
......@@ -944,26 +946,31 @@ GdbServerPortsGatherer::~GdbServerPortsGatherer()
QString GdbServerPortsGatherer::gdbServerChannel() const
{
const QString host = device()->sshParameters().host;
const QString host = m_device->sshParameters().host;
return QString("%1:%2").arg(host).arg(m_gdbServerPort.number());
}
QUrl GdbServerPortsGatherer::qmlServer() const
{
QUrl server = device()->toolControlChannel(IDevice::QmlControlChannel);
QUrl server = m_device->toolControlChannel(IDevice::QmlControlChannel);
server.setPort(m_qmlServerPort.number());
return server;
}
void GdbServerPortsGatherer::setDevice(IDevice::ConstPtr device)
{
m_device = device;
}
void GdbServerPortsGatherer::start()
{
appendMessage(tr("Checking available ports..."), NormalMessageFormat);
m_portsGatherer.start(device());
m_portsGatherer.start(m_device);
}
void GdbServerPortsGatherer::handlePortListReady()
{
Utils::PortList portList = device()->freePorts();
Utils::PortList portList = m_device->freePorts();
appendMessage(tr("Found %n free ports.", nullptr, portList.count()), NormalMessageFormat);
if (m_useGdbServer) {
m_gdbServerPort = m_portsGatherer.getNextFreePort(&portList);
......@@ -989,19 +996,38 @@ GdbServerRunner::GdbServerRunner(RunControl *runControl, GdbServerPortsGatherer
: SimpleTargetRunner(runControl), m_portsGatherer(portsGatherer)
{
setDisplayName("GdbServerRunner");
if (runControl->runnable().is<StandardRunnable>())
m_runnable = runControl->runnable().as<StandardRunnable>();
}
GdbServerRunner::~GdbServerRunner()
{
}
void GdbServerRunner::setRunnable(const StandardRunnable &runnable)
{
m_runnable = runnable;
}
void GdbServerRunner::setUseMulti(bool on)
{
m_useMulti = on;
}
void GdbServerRunner::setAttachPid(ProcessHandle pid)
{
m_pid = pid;
}
void GdbServerRunner::start()
{
QTC_ASSERT(m_portsGatherer, reportFailure(); return);
StandardRunnable r = runnable().as<StandardRunnable>();
QStringList args = QtcProcess::splitArgs(r.commandLineArguments, OsTypeLinux);
QString command;
StandardRunnable gdbserver;
gdbserver.environment = m_runnable.environment;
gdbserver.workingDirectory = m_runnable.workingDirectory;
QStringList args = QtcProcess::splitArgs(m_runnable.commandLineArguments, OsTypeLinux);
const bool isQmlDebugging = m_portsGatherer->useQmlServer();
const bool isCppDebugging = m_portsGatherer->useGdbServer();
......@@ -1010,21 +1036,24 @@ void GdbServerRunner::start()
args.prepend(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices,
m_portsGatherer->qmlServerPort()));
}
if (isQmlDebugging && !isCppDebugging) {
command = r.executable;
gdbserver.executable = m_runnable.executable; // FIXME: Case should not happen?
} else {
command = device()->debugServerPath();
if (command.isEmpty())
command = "gdbserver";
gdbserver.executable = device()->debugServerPath();
if (gdbserver.executable.isEmpty())
gdbserver.executable = "gdbserver";
args.clear();
args.append(QString("--multi"));
if (m_useMulti)
args.append("--multi");
if (m_pid.isValid())
args.append("--attach");
args.append(QString(":%1").arg(m_portsGatherer->gdbServerPort().number()));
if (m_pid.isValid())
args.append(QString::number(m_pid.pid()));
}
r.executable = command;
r.commandLineArguments = QtcProcess::joinArgs(args, OsTypeLinux);
gdbserver.commandLineArguments = QtcProcess::joinArgs(args, OsTypeLinux);
setRunnable(r);
SimpleTargetRunner::setRunnable(gdbserver);
appendMessage(tr("Starting gdbserver..."), NormalMessageFormat);
......
......@@ -161,6 +161,8 @@ public:
Utils::Port qmlServerPort() const { return m_qmlServerPort; }
QUrl qmlServer() const;
void setDevice(ProjectExplorer::IDevice::ConstPtr device);
private:
void start() override;
void handlePortListReady();
......@@ -170,6 +172,7 @@ private:
bool m_useQmlServer = false;
Utils::Port m_gdbServerPort;
Utils::Port m_qmlServerPort;
ProjectExplorer::IDevice::ConstPtr m_device;
};
class DEBUGGER_EXPORT GdbServerRunner : public ProjectExplorer::SimpleTargetRunner
......@@ -179,12 +182,20 @@ class DEBUGGER_EXPORT GdbServerRunner : public ProjectExplorer::SimpleTargetRunn
public:
explicit GdbServerRunner(ProjectExplorer::RunControl *runControl,
GdbServerPortsGatherer *portsGatherer);
~GdbServerRunner();
void setRunnable(const ProjectExplorer::StandardRunnable &runnable);
void setUseMulti(bool on);
void setAttachPid(Utils::ProcessHandle pid);
private:
void start() override;
GdbServerPortsGatherer *m_portsGatherer;
ProjectExplorer::StandardRunnable m_runnable;
Utils::ProcessHandle m_pid;
bool m_useMulti = true;
};
extern DEBUGGER_EXPORT const char GdbServerRunnerWorkerId[];
......
HEADERS += \
$$PWD/gdbengine.h \
$$PWD/startgdbserverdialog.h
$$PWD/gdbengine.h
SOURCES += \
$$PWD/gdbengine.cpp \
$$PWD/gdboptionspage.cpp \
$$PWD/startgdbserverdialog.cpp
$$PWD/gdboptionspage.cpp
......@@ -1330,11 +1330,12 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
notifyInferiorStopOk();
} else if (state() == EngineRunRequested) {
// This is gdb 7+'s initial *stopped in response to attach that
// appears before the ^done is seen.
// appears before the ^done is seen for local setups.
notifyEngineRunAndInferiorStopOk();
if (terminal())
if (terminal()) {
continueInferiorInternal();
return;
return;
}
} else {
QTC_CHECK(false);
}
......@@ -4267,7 +4268,11 @@ void GdbEngine::setupInferior()
const DebuggerRunParameters &rp = runParameters();
if (isAttachEngine()) {
if (rp.startMode == AttachToRemoteProcess) {
notifyInferiorSetupOk();
} else if (isAttachEngine()) {
// Task 254674 does not want to remove them
//qq->breakHandler()->removeAllBreakpoints();
handleInferiorPrepared();
......@@ -4377,7 +4382,6 @@ void GdbEngine::setupInferior()
} else if (isPlainEngine()) {
setEnvironmentVariables();
const DebuggerRunParameters &rp = runParameters();
if (!rp.inferior.workingDirectory.isEmpty())
runCommand({"cd " + rp.inferior.workingDirectory});
if (!rp.inferior.commandLineArguments.isEmpty()) {
......@@ -4395,9 +4399,18 @@ void GdbEngine::runEngine()
{
CHECK_STATE(EngineRunRequested);
if (isAttachEngine()) {
const DebuggerRunParameters &rp = runParameters();
if (rp.startMode == AttachToRemoteProcess) {
notifyEngineRunAndInferiorStopOk();
const qint64 pid = runParameters().attachPID.pid();
QString channel = rp.remoteChannel;
runCommand({"target remote " + channel});
} else if (isAttachEngine()) {
const qint64 pid = rp.attachPID.pid();
showStatusMessage(tr("Attaching to process %1.").arg(pid));
runCommand({"attach " + QString::number(pid),
[this](const DebuggerResponse &r) { handleAttach(r); }});
......@@ -4460,6 +4473,7 @@ void GdbEngine::handleAttach(const DebuggerResponse &response)
// InferiorStopOk, e.g. for "Attach to running application".
// The *stopped came in between sending the 'attach' and
// receiving its '^done'.
notifyEngineRunAndInferiorStopOk();
if (runParameters().continueAfterAttach)
continueInferiorInternal();
}
......@@ -4663,6 +4677,7 @@ void GdbEngine::handleSetTargetAsync(const DebuggerResponse &response)
void GdbEngine::callTargetRemote()
{
CHECK_STATE(InferiorSetupRequested);
QString channel = runParameters().remoteChannel;
// Don't touch channels with explicitly set protocols.
......
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "startgdbserverdialog.h"
#include <debugger/debuggerengine.h>
#include <debugger/debuggermainwindow.h>
#include <debugger/debuggerplugin.h>
#include <debugger/debuggerkitinformation.h>
#include <debugger/debuggerruncontrol.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
#include <projectexplorer/kitchooser.h>
#include <projectexplorer/devicesupport/deviceprocesslist.h>
#include <projectexplorer/devicesupport/deviceprocessesdialog.h>
#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
#include <ssh/sshremoteprocessrunner.h>
#include <utils/portlist.h>
#include <utils/qtcassert.h>
#include <QFileInfo>
using namespace Core;
using namespace ProjectExplorer;
using namespace QSsh;
using namespace Utils;
namespace Debugger {
namespace Internal {
class StartGdbServerDialogPrivate
{
public:
StartGdbServerDialogPrivate() : dialog(0), kit(0) {}
DeviceProcessesDialog *dialog;
bool attachToServer;
DeviceProcessItem process;
Kit *kit;
IDevice::ConstPtr device;
DeviceUsedPortsGatherer gatherer;
SshRemoteProcessRunner runner;
};
GdbServerStarter::GdbServerStarter(DeviceProcessesDialog *dlg, bool attachAfterServerStart)
: QObject(dlg)
{
d = new StartGdbServerDialogPrivate;
d->dialog = dlg;
d->kit = dlg->kitChooser()->currentKit();
d->process = dlg->currentProcess();
d->device = DeviceKitInformation::device(d->kit);
d->attachToServer = attachAfterServerStart;
}
GdbServerStarter::~GdbServerStarter()
{
delete d;
}
void GdbServerStarter::handleRemoteError(const QString &errorMsg)
{
AsynchronousMessageBox::critical(tr("Remote Error"), errorMsg);
}
void GdbServerStarter::portGathererError(const QString &text)
{
logMessage(tr("Could not retrieve list of free ports:"));
logMessage(text);
logMessage(tr("Process aborted"));
}
void GdbServerStarter::run()
{
QTC_ASSERT(d->device, return);
connect(&d->gatherer, &DeviceUsedPortsGatherer::error,
this, &GdbServerStarter::portGathererError);
connect(&d->gatherer, &DeviceUsedPortsGatherer::portListReady,
this, &GdbServerStarter::portListReady);
d->gatherer.start(d->device);
}
void GdbServerStarter::portListReady()
{
PortList ports = d->device->freePorts();
const Port port = d->gatherer.getNextFreePort(&ports);
if (!port.isValid()) {
QTC_ASSERT(false, /**/);
emit logMessage(tr("Process aborted"));
return;
}
connect(&d->runner, &SshRemoteProcessRunner::connectionError,
this, &GdbServerStarter::handleConnectionError);
connect(&d->runner, &SshRemoteProcessRunner::processStarted,
this, &GdbServerStarter::handleProcessStarted);
connect(&d->runner, &SshRemoteProcessRunner::readyReadStandardOutput,
this, &GdbServerStarter::handleProcessOutputAvailable);
connect(&d->runner, &SshRemoteProcessRunner::readyReadStandardError,
this, &GdbServerStarter::handleProcessErrorOutput);
connect(&d->runner, &SshRemoteProcessRunner::processClosed,
this, &GdbServerStarter::handleProcessClosed);
QByteArray gdbServerPath = d->device->debugServerPath().toUtf8();
if (gdbServerPath.isEmpty())
gdbServerPath = "gdbserver";
QByteArray cmd = gdbServerPath + " --attach :"
+ QByteArray::number(port.number()) + ' ' + QByteArray::number(d->process.pid);
logMessage(tr("Running command: %1").arg(QString::fromLatin1(cmd)));
d->runner.run(cmd, d->device->sshParameters());
}
void GdbServerStarter::handleConnectionError()
{
logMessage(tr("Connection error: %1").arg(d->runner.lastConnectionErrorString()));
}
void GdbServerStarter::handleProcessStarted()
{
logMessage(tr("Starting gdbserver..."));
}
void GdbServerStarter::handleProcessOutputAvailable()
{
logMessage(QString::fromUtf8(d->runner.readAllStandardOutput().trimmed()));
}
void GdbServerStarter::handleProcessErrorOutput()
{
const QByteArray ba = d->runner.readAllStandardError();
logMessage(QString::fromUtf8(ba.trimmed()));
// "Attached; pid = 16740"
// "Listening on port 10000"
foreach (const QByteArray &line, ba.split('\n')) {
if (line.startsWith("Listening on port")) {
const int port = line.mid(18).trimmed().toInt();
logMessage(tr("Port %1 is now accessible.").arg(port));
logMessage(tr("Server started on %1:%2")
.arg(d->device->sshParameters().host).arg(port));
if (d->attachToServer)
attach(port);
}
}
}
void GdbServerStarter::attach(int port)
{
QString sysroot = SysRootKitInformation::sysRoot(d->kit).toString();
QString binary;
QString localExecutable;
QString candidate = sysroot + d->process.exe;
if (QFileInfo::exists(candidate))
localExecutable = candidate;
if (localExecutable.isEmpty()) {
binary = d->process.cmdLine.section(QLatin1Char(' '), 0, 0);
candidate = sysroot + QLatin1Char('/') + binary;
if (QFileInfo::exists(candidate))
localExecutable = candidate;
}
if (localExecutable.isEmpty()) {
candidate = sysroot + QLatin1String("/usr/bin/") + binary;
if (QFileInfo::exists(candidate))
localExecutable = candidate;
}
if (localExecutable.isEmpty()) {
candidate = sysroot + QLatin1String("/bin/") + binary;
if (QFileInfo::exists(candidate))
localExecutable = candidate;
}
if (localExecutable.isEmpty()) {
AsynchronousMessageBox::warning(tr("Warning"),
tr("Cannot find local executable for remote process \"%1\".")
.arg(d->process.exe));
return;
}
QList<Abi> abis = Abi::abisOfBinary(FileName::fromString(localExecutable));
if (abis.isEmpty()) {
AsynchronousMessageBox::warning(tr("Warning"),
tr("Cannot find ABI for remote process \"%1\".")
.arg(d->process.exe));
return;
}
QString remoteChannel = QString("%1:%2").arg(d->device->sshParameters().host).arg(port);
auto runControl = new RunControl(nullptr, ProjectExplorer::Constants::DEBUG_RUN_MODE);
auto debugger = new DebuggerRunTool(runControl, d->kit);
debugger->setRemoteChannel(remoteChannel);
debugger->setRunControlName(tr("Remote: \"%1\"").arg(remoteChannel));
debugger->setInferiorExecutable(localExecutable);
debugger->setStartMode(AttachToRemoteServer);
debugger->setCloseMode(KillAtClose);
debugger->startRunControl();
}
void GdbServerStarter::handleProcessClosed(int status)
{
logMessage(tr("Process gdbserver finished. Status: %1").arg(status));
}
void GdbServerStarter::logMessage(const QString &line)
{
d->dialog->logMessage(line);
}
} // namespace Internal
} // namespace Debugger
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QObject>
namespace ProjectExplorer { class DeviceProcessesDialog; }
namespace Debugger {
namespace Internal {
class StartGdbServerDialogPrivate;
class GdbServerStarter : public QObject
{
Q_OBJECT
public:
GdbServerStarter(ProjectExplorer::DeviceProcessesDialog *dlg,
bool attachAfterServerStart);
~GdbServerStarter();
void run();
private:
void handleRemoteError(const QString &errorMessage);
void portGathererError(const QString &errorMessage);
void portListReady();
void handleProcessClosed(int);
void handleProcessErrorOutput();
void handleProcessOutputAvailable();
void handleProcessStarted();
void handleConnectionError();
void attach(int port);
void logMessage(const QString &line);
StartGdbServerDialogPrivate *d;
};
} // namespace Internal
} // namespace Debugger
......@@ -1384,24 +1384,14 @@ bool Runnable::canReUseOutputPane(const Runnable &other) const
}
// FIXME: Remove once ApplicationLauncher signalling does not depend on device.
static bool isSynchronousLauncher(RunControl *runControl)
{
RunConfiguration *runConfig = runControl->runConfiguration();
Target *target = runConfig ? runConfig->target() : nullptr;
Kit *kit = target ? target->kit() : nullptr;
Core::Id deviceId = DeviceTypeKitInformation::deviceTypeId(kit);
return !deviceId.isValid() || deviceId == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
}
// SimpleTargetRunner
SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl)
: RunWorker(runControl)
{
setDisplayName("SimpleTargetRunner");
m_runnable = runControl->runnable();
m_runnable = runControl->runnable(); // Default value. Can be overridden using setRunnable.
m_device = runControl->device(); // Default value. Can be overridden using setDevice.
}
void SimpleTargetRunner::start()
......@@ -1409,7 +1399,8 @@ void SimpleTargetRunner::start()
m_stopReported = false;