Files
qt-creator/src/plugins/qnx/qnxdebugsupport.cpp

289 lines
9.4 KiB
C++
Raw Normal View History

/****************************************************************************
**
** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
** Contact: KDAB (info@kdab.com)
**
** 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 "qnxdebugsupport.h"
#include "qnxconstants.h"
#include "qnxdevice.h"
#include "qnxrunconfiguration.h"
#include "slog2inforunner.h"
#include "qnxqtversion.h"
#include "qnxutils.h"
#include <coreplugin/icore.h>
#include <debugger/debuggerkitinformation.h>
#include <debugger/debuggerruncontrol.h>
#include <projectexplorer/applicationlauncher.h>
#include <projectexplorer/devicesupport/deviceprocessesdialog.h>
#include <projectexplorer/devicesupport/deviceprocesslist.h>
#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/kitchooser.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/runconfigurationaspects.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
#include <qmldebug/qmldebugcommandlinearguments.h>
#include <qtsupport/qtkitinformation.h>
#include <utils/pathchooser.h>
#include <utils/portlist.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <QDir>
#include <QFormLayout>
#include <QLabel>
#include <QVBoxLayout>
using namespace Debugger;
using namespace ProjectExplorer;
using namespace Utils;
namespace Qnx {
namespace Internal {
static QStringList searchPaths(Kit *kit)
{
auto qtVersion = dynamic_cast<QnxQtVersion *>(QtSupport::QtKitAspect::qtVersion(kit));
if (!qtVersion)
return {};
const QDir pluginDir(qtVersion->qmakeProperty("QT_INSTALL_PLUGINS"));
const QStringList pluginSubDirs = pluginDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
QStringList searchPaths;
for (const QString &dir : pluginSubDirs)
searchPaths << qtVersion->qmakeProperty("QT_INSTALL_PLUGINS") + '/' + dir;
searchPaths << qtVersion->qmakeProperty("QT_INSTALL_LIBS");
searchPaths << qtVersion->qnxTarget().appendPath(qtVersion->cpuDir()).appendPath("lib")
.toString();
searchPaths << qtVersion->qnxTarget().appendPath(qtVersion->cpuDir()).appendPath("usr/lib")
.toString();
return searchPaths;
}
// QnxDebuggeeRunner
class QnxDebuggeeRunner : public ProjectExplorer::SimpleTargetRunner
{
public:
QnxDebuggeeRunner(RunControl *runControl, GdbServerPortsGatherer *portsGatherer)
: SimpleTargetRunner(runControl), m_portsGatherer(portsGatherer)
{
setId("QnxDebuggeeRunner");
}
private:
void start() final
{
Runnable r = runnable();
QStringList arguments;
if (m_portsGatherer->useGdbServer()) {
Port pdebugPort = m_portsGatherer->gdbServerPort();
r.executable = Constants::QNX_DEBUG_EXECUTABLE;
arguments.append(pdebugPort.toString());
}
if (m_portsGatherer->useQmlServer()) {
arguments.append(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices,
m_portsGatherer->qmlServerPort()));
}
arguments.append(QtcProcess::splitArgs(r.commandLineArguments));
r.commandLineArguments = QtcProcess::joinArgs(arguments);
setRunnable(r);
SimpleTargetRunner::start();
}
GdbServerPortsGatherer *m_portsGatherer;
};
// QnxDebugSupport
QnxDebugSupport::QnxDebugSupport(RunControl *runControl)
: DebuggerRunTool(runControl)
{
setId("QnxDebugSupport");
appendMessage(tr("Preparing remote side..."), LogMessageFormat);
setUsePortsGatherer(isCppDebugging(), isQmlDebugging());
auto debuggeeRunner = new QnxDebuggeeRunner(runControl, portsGatherer());
debuggeeRunner->addStartDependency(portsGatherer());
auto slog2InfoRunner = new Slog2InfoRunner(runControl);
debuggeeRunner->addStartDependency(slog2InfoRunner);
addStartDependency(debuggeeRunner);
Avoid some visible uses of RunControl::runConfiguration() For a long time, probably from the very beginning, a RunControl was meant to hold (a copy of) data needed for its operation, that was valid at the time of its construction, to be resilient in cases where RunConfiguration setting were changed while the RunControl was running, or to properly re-run with the original settings. Unfortunately, the task was repetitive, as RunConfiguration classes had no generic access to properties / "aspects" and there was was the runConfiguration() accessor (probably for mostly unrelated reasons in the output pane handling) which made the idea of just casting that to the original runConfiguration and access the data directly there appealing, with all the expected consequences. This patch here partially addresses the issue by copying some more of the related data at RunControl construction time and adjust the using code, avoiding most uses of the runConfiguration() accessor in a mostly mechanical matter. Complete removal appears possible, but will be less mechanical in "difficult" plugins like ios, so this is left for later. The new accessors in RunControl are very much ad-hoc, leaving room for improvement, e.g. by consolidating the access to the run config settings aspects with the other runconfig aspects or similar. For now the goal is to remove the runConfiguration() accessor, and to as much as possible fixed data after RunControl setup is finished. Next step would be to officially allow construction of RunControls without a specific RunConfiguration by setting the necessary data independently, removing the need for the various workarounds that are currently used for the purpose of faking (parts of) the effect of the non-existing RunConfiguration or refusing to operate at all, even if it would be possible. Change-Id: If8e5596da8422c70e90f97270389adbe6d0b46f2 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
2019-03-11 15:42:43 +01:00
Kit *k = runControl->kit();
setStartMode(AttachToRemoteServer);
setCloseMode(KillAtClose);
setUseCtrlCStub(true);
setSolibSearchPath(searchPaths(k));
if (auto qtVersion = dynamic_cast<QnxQtVersion *>(QtSupport::QtKitAspect::qtVersion(k)))
setSysRoot(qtVersion->qnxTarget());
}
// QnxAttachDebugDialog
class QnxAttachDebugDialog : public DeviceProcessesDialog
{
public:
QnxAttachDebugDialog(KitChooser *kitChooser)
: DeviceProcessesDialog(kitChooser, Core::ICore::dialogParent())
{
auto sourceLabel = new QLabel(QnxDebugSupport::tr("Project source directory:"), this);
m_projectSource = new PathChooser(this);
m_projectSource->setExpectedKind(PathChooser::ExistingDirectory);
auto binaryLabel = new QLabel(QnxDebugSupport::tr("Local executable:"), this);
m_localExecutable = new PathChooser(this);
m_localExecutable->setExpectedKind(PathChooser::File);
auto formLayout = new QFormLayout;
formLayout->addRow(sourceLabel, m_projectSource);
formLayout->addRow(binaryLabel, m_localExecutable);
auto mainLayout = dynamic_cast<QVBoxLayout*>(layout());
QTC_ASSERT(mainLayout, return);
mainLayout->insertLayout(mainLayout->count() - 2, formLayout);
}
QString projectSource() const { return m_projectSource->path(); }
QString localExecutable() const { return m_localExecutable->path(); }
private:
PathChooser *m_projectSource;
PathChooser *m_localExecutable;
};
// QnxAttachDebugSupport
class PDebugRunner : public ProjectExplorer::SimpleTargetRunner
{
public:
PDebugRunner(RunControl *runControl, GdbServerPortsGatherer *portsGatherer)
: SimpleTargetRunner(runControl), m_portsGatherer(portsGatherer)
{
setId("PDebugRunner");
addStartDependency(m_portsGatherer);
}
private:
void start() final
{
Port pdebugPort = m_portsGatherer->gdbServerPort();
Runnable r;
r.executable = Constants::QNX_DEBUG_EXECUTABLE;
r.commandLineArguments = pdebugPort.toString();
setRunnable(r);
SimpleTargetRunner::start();
}
GdbServerPortsGatherer *m_portsGatherer;
};
QnxAttachDebugSupport::QnxAttachDebugSupport(RunControl *runControl)
: DebuggerRunTool(runControl)
{
setId("QnxAttachDebugSupport");
setUsePortsGatherer(isCppDebugging(), isQmlDebugging());
if (isCppDebugging()) {
auto pdebugRunner = new PDebugRunner(runControl, portsGatherer());
addStartDependency(pdebugRunner);
}
}
void QnxAttachDebugSupport::showProcessesDialog()
{
auto kitChooser = new KitChooser;
kitChooser->setKitPredicate([](const Kit *k) {
return k->isValid() && DeviceTypeKitAspect::deviceTypeId(k) == Constants::QNX_QNX_OS_TYPE;
});
QnxAttachDebugDialog dlg(kitChooser);
dlg.addAcceptButton(DeviceProcessesDialog::tr("&Attach to Process"));
dlg.showAllDevices();
if (dlg.exec() == QDialog::Rejected)
return;
Kit *kit = kitChooser->currentKit();
if (!kit)
return;
// FIXME: That should be somehow related to the selected kit.
auto startRunConfig = RunConfiguration::startupRunConfiguration();
auto runConfig = qobject_cast<QnxRunConfiguration *>(startRunConfig);
if (!runConfig)
return;
DeviceProcessItem process = dlg.currentProcess();
const int pid = process.pid;
// QString projectSourceDirectory = dlg.projectSource();
QString localExecutable = dlg.localExecutable();
if (localExecutable.isEmpty()) {
if (auto aspect = runConfig->aspect<SymbolFileAspect>())
localExecutable = aspect->fileName().toString();
}
auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE);
runControl->setRunConfiguration(runConfig);
auto debugger = new QnxAttachDebugSupport(runControl);
debugger->setStartMode(AttachToRemoteServer);
debugger->setCloseMode(DetachAtClose);
debugger->setSymbolFile(localExecutable);
debugger->setUseCtrlCStub(true);
debugger->setAttachPid(pid);
// setRunControlName(tr("Remote: \"%1\" - Process %2").arg(remoteChannel).arg(m_process.pid));
debugger->setRunControlName(tr("Remote QNX process %1").arg(pid));
debugger->setSolibSearchPath(searchPaths(kit));
if (auto qtVersion = dynamic_cast<QnxQtVersion *>(QtSupport::QtKitAspect::qtVersion(kit)))
debugger->setSysRoot(qtVersion->qnxTarget());
debugger->setUseContinueInsteadOfRun(true);
ProjectExplorerPlugin::startRunControl(runControl);
}
} // namespace Internal
} // namespace Qnx