Debugger: Dissolve DebugServerPortsGatherer

Use a suitable amount of individual SubChannelProviders instead.

Remove the lumping of the perf channel and gdb/lldb channel in the
users.

Change-Id: I47d449e933799e1a10df4801dfbe99653f168f56
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
hjk
2024-09-30 12:12:59 +02:00
parent a26119b920
commit b187d5ffd8
5 changed files with 159 additions and 176 deletions

View File

@@ -34,7 +34,6 @@ public:
bool usePerf, bool useGdbServer, bool useQmlServer,
QmlDebug::QmlDebugServicesPreset qmlServices)
: RunWorker(runControl),
m_usePerf(usePerf), m_useGdbServer(useGdbServer), m_useQmlServer(useQmlServer),
m_qmlServices(qmlServices)
{
setId("QdbDebuggeeRunner");
@@ -49,52 +48,54 @@ public:
appendMessage(m_launcher.readAllStandardError(), StdErrFormat);
});
m_portsGatherer = new DebugServerPortsGatherer(runControl);
m_portsGatherer->setUseGdbServer(useGdbServer || usePerf);
m_portsGatherer->setUseQmlServer(useQmlServer);
addStartDependency(m_portsGatherer);
if (useGdbServer) {
m_debugChannelProvider = new SubChannelProvider(runControl);
addStartDependency(m_debugChannelProvider);
}
QUrl perfServer() const { return m_portsGatherer->gdbServer(); }
QUrl gdbServer() const { return m_portsGatherer->gdbServer(); }
QUrl qmlServer() const { return m_portsGatherer->qmlServer(); }
if (useQmlServer) {
m_qmlChannelProvider = new SubChannelProvider(runControl);
addStartDependency(m_qmlChannelProvider);
}
if (usePerf) {
m_perfChannelProvider = new SubChannelProvider(runControl);
addStartDependency(m_perfChannelProvider);
}
}
void start() override
{
const int perfPort = m_portsGatherer->gdbServer().port();
const int gdbServerPort = m_portsGatherer->gdbServer().port();
const int qmlServerPort = m_portsGatherer->qmlServer().port();
int lowerPort = 0;
int upperPort = 0;
CommandLine cmd;
cmd.setExecutable(device()->filePath(Constants::AppcontrollerFilepath));
if (m_useGdbServer) {
if (m_debugChannelProvider) {
cmd.addArg("--debug-gdb");
lowerPort = upperPort = gdbServerPort;
lowerPort = upperPort = m_debugChannelProvider->channel().port();
}
if (m_useQmlServer) {
if (m_qmlChannelProvider) {
cmd.addArg("--debug-qml");
cmd.addArg("--qml-debug-services");
cmd.addArg(QmlDebug::qmlDebugServices(m_qmlServices));
lowerPort = upperPort = qmlServerPort;
lowerPort = upperPort = m_qmlChannelProvider->channel().port();
}
if (m_useGdbServer && m_useQmlServer) {
if (gdbServerPort + 1 != qmlServerPort) {
if (m_debugChannelProvider && m_qmlChannelProvider) {
lowerPort = m_debugChannelProvider->channel().port();
upperPort = m_qmlChannelProvider->channel().port();
if (lowerPort + 1 != upperPort) {
reportFailure("Need adjacent free ports for combined C++/QML debugging");
return;
}
lowerPort = gdbServerPort;
upperPort = qmlServerPort;
}
if (m_usePerf) {
if (m_perfChannelProvider) {
const Store perfArgs = runControl()->settingsData(PerfProfiler::Constants::PerfSettingsId);
const QString recordArgs = perfArgs[PerfProfiler::Constants::PerfRecordArgsId].toString();
cmd.addArg("--profile-perf");
cmd.addArgs(recordArgs, CommandLine::Raw);
lowerPort = upperPort = perfPort;
lowerPort = upperPort = m_perfChannelProvider->channel().port();
}
cmd.addArg("--port-range");
cmd.addArg(QString("%1-%2").arg(lowerPort).arg(upperPort));
@@ -109,10 +110,14 @@ public:
void stop() override { m_launcher.close(); }
private:
Debugger::DebugServerPortsGatherer *m_portsGatherer = nullptr;
bool m_usePerf;
bool m_useGdbServer;
bool m_useQmlServer;
friend class QdbDeviceDebugSupport;
friend class QdbDeviceQmlProfilerSupport;
friend class QdbDeviceQmlToolingSupport;
friend class QdbDevicePerfProfilerSupport;
Debugger::SubChannelProvider *m_debugChannelProvider = nullptr;
Debugger::SubChannelProvider *m_qmlChannelProvider = nullptr;
Debugger::SubChannelProvider *m_perfChannelProvider = nullptr;
QmlDebug::QmlDebugServicesPreset m_qmlServices;
Process m_launcher;
};
@@ -167,8 +172,10 @@ void QdbDeviceDebugSupport::start()
{
setStartMode(Debugger::AttachToRemoteServer);
setCloseMode(KillAndExitMonitorAtClose);
setRemoteChannel(m_debuggee->gdbServer());
setQmlServer(m_debuggee->qmlServer());
if (SubChannelProvider *provider = m_debuggee->m_debugChannelProvider)
setRemoteChannel(provider->channel());
if (SubChannelProvider *provider = m_debuggee->m_qmlChannelProvider)
setQmlServer(provider->channel());
setUseContinueInsteadOfRun(true);
setContinueAfterAttach(true);
addSolibSearchDir("%{sysroot}/system/lib");
@@ -214,7 +221,8 @@ QdbDeviceQmlToolingSupport::QdbDeviceQmlToolingSupport(RunControl *runControl)
void QdbDeviceQmlToolingSupport::start()
{
m_worker->recordData("QmlServerUrl", m_runner->qmlServer());
QTC_ASSERT(m_runner->m_qmlChannelProvider, reportFailure({}));
m_worker->recordData("QmlServerUrl", m_runner->m_qmlChannelProvider->channel());
reportStarted();
}
@@ -244,7 +252,8 @@ QdbDevicePerfProfilerSupport::QdbDevicePerfProfilerSupport(RunControl *runContro
void QdbDevicePerfProfilerSupport::start()
{
runControl()->setProperty("PerfConnection", m_profilee->perfServer());
QTC_ASSERT(m_profilee->m_perfChannelProvider, reportFailure({}));
runControl()->setProperty("PerfConnection", m_profilee->m_perfChannelProvider->channel());
reportStarted();
}

View File

@@ -156,7 +156,8 @@ class DebuggerRunToolPrivate
{
public:
QPointer<CoreUnpacker> coreUnpacker;
QPointer<DebugServerPortsGatherer> portsGatherer;
QPointer<SubChannelProvider> debugChannelProvider;
QPointer<SubChannelProvider> qmlChannelProvider;
bool addQmlServerInferiorCommandLineArgumentIfNeeded = false;
int snapshotCounter = 0;
int engineStartsNeeded = 0;
@@ -463,9 +464,11 @@ void DebuggerRunTool::continueAfterTerminalStart()
{
TaskHub::clearTasks(Constants::TASK_CATEGORY_DEBUGGER_RUNTIME);
if (d->portsGatherer) {
setRemoteChannel(d->portsGatherer->gdbServer());
setQmlServer(d->portsGatherer->qmlServer());
if (d->debugChannelProvider)
setRemoteChannel(d->debugChannelProvider->channel());
if (d->qmlChannelProvider) {
setQmlServer(d->qmlChannelProvider->channel());
if (d->addQmlServerInferiorCommandLineArgumentIfNeeded
&& m_runParameters.isQmlDebugging
&& m_runParameters.isCppDebugging()) {
@@ -755,17 +758,39 @@ bool DebuggerRunTool::isQmlDebugging() const
void DebuggerRunTool::setUsePortsGatherer(bool useCpp, bool useQml)
{
QTC_ASSERT(!d->portsGatherer, reportFailure(); return);
runControl()->enablePortsGatherer();
d->portsGatherer = new DebugServerPortsGatherer(runControl());
d->portsGatherer->setUseGdbServer(useCpp);
d->portsGatherer->setUseQmlServer(useQml);
addStartDependency(d->portsGatherer);
if (useCpp) {
QTC_ASSERT(!d->debugChannelProvider, reportFailure(); return);
d->debugChannelProvider = new SubChannelProvider(runControl());
addStartDependency(d->debugChannelProvider);
}
if (useQml) {
QTC_ASSERT(!d->qmlChannelProvider, reportFailure(); return);
d->qmlChannelProvider = new SubChannelProvider(runControl());
addStartDependency(d->qmlChannelProvider);
}
}
DebugServerPortsGatherer *DebuggerRunTool::portsGatherer() const
SubChannelProvider *DebuggerRunTool::debugChannelProvider() const
{
return d->portsGatherer;
return d->debugChannelProvider;
}
QUrl DebuggerRunTool::debugChannel() const
{
QTC_ASSERT(d->debugChannelProvider, return {});
return d->debugChannelProvider->channel();
}
SubChannelProvider *DebuggerRunTool::qmlChannelProvider() const
{
return d->qmlChannelProvider;
}
QUrl DebuggerRunTool::qmlChannel() const
{
QTC_ASSERT(d->qmlChannelProvider, return {});
return d->qmlChannelProvider->channel();
}
void DebuggerRunTool::setSolibSearchPath(const Utils::FilePaths &list)
@@ -1022,50 +1047,6 @@ void DebuggerRunTool::showMessage(const QString &msg, int channel, int timeout)
}
}
namespace Internal {
/*!
\class Debugger::SubChannelProvider
\internal
This is a helper RunWorker implementation to either use or not
use port forwarding for one SubChannel in the ChannelProvider
implementation.
By default it is assumed that no forwarding is needed, i.e.
end points provided by the shared endpoint resource provider
are directly accessible.
*/
class SubChannelProvider : public RunWorker
{
public:
SubChannelProvider(RunControl *runControl)
: RunWorker(runControl)
{
setId("SubChannelProvider");
}
void start() final
{
m_channel.setScheme(urlTcpScheme());
if (device()->extraData(RemoteLinux::Constants::SshForwardDebugServerPort).toBool())
m_channel.setHost("localhost");
else
m_channel.setHost(device()->toolControlChannel(IDevice::ControlChannelHint()).host());
m_channel.setPort(runControl()->findEndPoint().port());
reportStarted();
}
QUrl channel() const { return m_channel; }
private:
QUrl m_channel;
};
} // Internal
////////////////////////////////////////////////////////////////////////
//
// Externally visible helper.
@@ -1073,21 +1054,23 @@ private:
////////////////////////////////////////////////////////////////////////
/*!
\class Debugger::DebugServerPortsGatherer
\class Debugger::SubChannelProvider
\internal
The class implements a \c RunWorker to provide
to provide a set of urls indicating usable connection end
The class implements a \c RunWorker to provide a url
indicating usable connection end
points for 'server-using' tools (typically one, like plain
gdbserver and the Qml tooling, but two for mixed debugging).
Urls can describe local or tcp servers that are directly
accessible to the host tools.
By default it is assumed that no forwarding is needed, i.e.
end points provided by the shared endpoint resource provider
are directly accessible.
The tool implementations can assume that any needed port
forwarding setup is setup and handled transparently by
a \c DebugServerPortsGatherer instance.
a \c SubChannelProvider instance.
If there are multiple subchannels needed that need to share a
common set of resources on the remote side, a device implementation
@@ -1102,28 +1085,21 @@ private:
forwarding.
*/
DebugServerPortsGatherer::DebugServerPortsGatherer(RunControl *runControl)
SubChannelProvider::SubChannelProvider(RunControl *runControl)
: RunWorker(runControl)
{
setId("DebugServerPortsGatherer");
m_gdbChannelProvider = new Internal::SubChannelProvider(runControl);
addStartDependency(m_gdbChannelProvider);
m_qmlChannelProvider = new Internal::SubChannelProvider(runControl);
addStartDependency(m_qmlChannelProvider);
setId("SubChannelProvider");
}
DebugServerPortsGatherer::~DebugServerPortsGatherer() = default;
QUrl DebugServerPortsGatherer::gdbServer() const
void SubChannelProvider::start()
{
return m_gdbChannelProvider->channel();
}
QUrl DebugServerPortsGatherer::qmlServer() const
{
return m_qmlChannelProvider->channel();
m_channel.setScheme(urlTcpScheme());
if (device()->extraData(RemoteLinux::Constants::SshForwardDebugServerPort).toBool())
m_channel.setHost("localhost");
else
m_channel.setHost(device()->toolControlChannel(IDevice::ControlChannelHint()).host());
m_channel.setPort(runControl()->findEndPoint().port());
reportStarted();
}
void DebuggerRunTool::startDebugServerIfNeededAndContinueStartup()
@@ -1135,19 +1111,14 @@ void DebuggerRunTool::startDebugServerIfNeededAndContinueStartup()
// FIXME: Indentation intentionally wrong to keep diff in gerrit small. Will fix later.
QTC_ASSERT(portsGatherer(), reportFailure(); return);
const bool isQmlDebugging = portsGatherer()->useQmlServer();
const bool isCppDebugging = portsGatherer()->useGdbServer();
CommandLine commandLine = m_runParameters.inferior.command;
CommandLine cmd;
if (isQmlDebugging && !isCppDebugging) {
if (d->qmlChannelProvider && !d->debugChannelProvider) {
// FIXME: Case should not happen?
cmd.setExecutable(commandLine.executable());
cmd.addArg(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices,
portsGatherer()->qmlServer()));
d->qmlChannelProvider->channel()));
cmd.addArgs(commandLine.arguments(), CommandLine::Raw);
} else {
cmd.setExecutable(device()->debugServerPath());
@@ -1191,14 +1162,15 @@ void DebuggerRunTool::startDebugServerIfNeededAndContinueStartup()
}
}
}
QTC_ASSERT(d->debugChannelProvider, reportFailure({}));
if (cmd.executable().baseName().contains("lldb-server")) {
cmd.addArg("platform");
cmd.addArg("--listen");
cmd.addArg(QString("*:%1").arg(portsGatherer()->gdbServer().port()));
cmd.addArg(QString("*:%1").arg(d->debugChannelProvider->channel().port()));
cmd.addArg("--server");
} else if (cmd.executable().baseName() == "debugserver") {
const QString ipAndPort("`echo $SSH_CLIENT | cut -d ' ' -f 1`:%1");
cmd.addArgs(ipAndPort.arg(portsGatherer()->gdbServer().port()), CommandLine::Raw);
cmd.addArgs(ipAndPort.arg(d->debugChannelProvider->channel().port()), CommandLine::Raw);
if (d->serverAttachPid.isValid())
cmd.addArgs({"--attach", QString::number(d->serverAttachPid.pid())});
@@ -1211,7 +1183,7 @@ void DebuggerRunTool::startDebugServerIfNeededAndContinueStartup()
if (d->serverAttachPid.isValid())
cmd.addArg("--attach");
const auto port = portsGatherer()->gdbServer().port();
const auto port = d->debugChannelProvider->channel().port();
cmd.addArg(QString(":%1").arg(port));
if (device()->extraData(RemoteLinux::Constants::SshForwardDebugServerPort).toBool()) {

View File

@@ -15,12 +15,9 @@
namespace Debugger {
namespace Internal {
class DebuggerRunToolPrivate;
class SubChannelProvider;
}
namespace Internal { class DebuggerRunToolPrivate; }
class DebugServerPortsGatherer;
class SubChannelProvider;
class DEBUGGER_EXPORT DebuggerRunTool : public ProjectExplorer::RunWorker
{
@@ -85,12 +82,17 @@ public:
Internal::DebuggerRunParameters &runParameters() { return m_runParameters; }
QUrl debugChannel() const;
SubChannelProvider *debugChannelProvider() const;
QUrl qmlChannel() const;
SubChannelProvider *qmlChannelProvider() const;
protected:
bool isCppDebugging() const;
bool isQmlDebugging() const;
void setUsePortsGatherer(bool useCpp, bool useQml);
DebugServerPortsGatherer *portsGatherer() const;
void addSolibSearchDir(const QString &str);
void addQmlServerInferiorCommandLineArgumentIfNeeded();
@@ -127,25 +129,17 @@ private:
Internal::DebuggerRunParameters m_runParameters;
};
class DEBUGGER_EXPORT DebugServerPortsGatherer : public ProjectExplorer::RunWorker
class DEBUGGER_EXPORT SubChannelProvider : public ProjectExplorer::RunWorker
{
public:
explicit DebugServerPortsGatherer(ProjectExplorer::RunControl *runControl);
~DebugServerPortsGatherer() override;
explicit SubChannelProvider(ProjectExplorer::RunControl *runControl);
void setUseGdbServer(bool useIt) { m_useGdbServer = useIt; }
bool useGdbServer() const { return m_useGdbServer; }
QUrl gdbServer() const;
void start() final;
void setUseQmlServer(bool useIt) { m_useQmlServer = useIt; }
bool useQmlServer() const { return m_useQmlServer; }
QUrl qmlServer() const;
QUrl channel() const { return m_channel; }
private:
bool m_useGdbServer = false;
bool m_useQmlServer = false;
Internal::SubChannelProvider *m_gdbChannelProvider;
Internal::SubChannelProvider *m_qmlChannelProvider;
QUrl m_channel;
};
class DebuggerRunWorkerFactory final : public ProjectExplorer::RunWorkerFactory

View File

@@ -76,26 +76,25 @@ static QStringList searchPaths(Kit *kit)
class QnxDebuggeeRunner : public ProjectExplorer::SimpleTargetRunner
{
public:
QnxDebuggeeRunner(RunControl *runControl, DebugServerPortsGatherer *portsGatherer)
QnxDebuggeeRunner(RunControl *runControl, DebuggerRunTool *debugger)
: SimpleTargetRunner(runControl)
{
setId("QnxDebuggeeRunner");
setStartModifier([this, portsGatherer] {
setStartModifier([this, debugger] {
CommandLine cmd = commandLine();
QStringList arguments;
if (portsGatherer->useGdbServer()) {
int pdebugPort = portsGatherer->gdbServer().port();
if (SubChannelProvider *provider = debugger->debugChannelProvider()) {
int pdebugPort = provider->channel().port();
cmd.setExecutable(device()->filePath(QNX_DEBUG_EXECUTABLE));
arguments.append(QString::number(pdebugPort));
}
if (portsGatherer->useQmlServer()) {
if (SubChannelProvider *provider = debugger->qmlChannelProvider()) {
arguments.append(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices,
portsGatherer->qmlServer()));
provider->channel()));
}
cmd.setArguments(ProcessArgs::joinArgs(arguments));
setCommandLine(cmd);
});
}
};
@@ -114,8 +113,7 @@ public:
setUsePortsGatherer(isCppDebugging(), isQmlDebugging());
auto debuggeeRunner = new QnxDebuggeeRunner(runControl, portsGatherer());
debuggeeRunner->addStartDependency(portsGatherer());
auto debuggeeRunner = new QnxDebuggeeRunner(runControl, this);
auto slog2InfoRunner = new Slog2InfoRunner(runControl);
debuggeeRunner->addStartDependency(slog2InfoRunner);
@@ -175,14 +173,13 @@ private:
class PDebugRunner : public ProjectExplorer::SimpleTargetRunner
{
public:
PDebugRunner(RunControl *runControl, DebugServerPortsGatherer *portsGatherer)
PDebugRunner(RunControl *runControl, DebuggerRunTool *debugger)
: SimpleTargetRunner(runControl)
{
setId("PDebugRunner");
addStartDependency(portsGatherer);
setStartModifier([this, portsGatherer] {
const int pdebugPort = portsGatherer->gdbServer().port();
setStartModifier([this, debugger] {
const int pdebugPort = debugger->debugChannel().port();
setCommandLine({QNX_DEBUG_EXECUTABLE, {QString::number(pdebugPort)}});
});
}
@@ -199,7 +196,7 @@ public:
setUseCtrlCStub(true);
if (isCppDebugging()) {
auto pdebugRunner = new PDebugRunner(runControl, portsGatherer());
auto pdebugRunner = new PDebugRunner(runControl, this);
addStartDependency(pdebugRunner);
}
}

View File

@@ -101,7 +101,6 @@ public:
bool usePerf, bool useGdbServer, bool useQmlServer,
QmlDebug::QmlDebugServicesPreset qmlServices)
: SimpleTargetRunner(runControl),
m_usePerf(usePerf), m_useGdbServer(useGdbServer), m_useQmlServer(useQmlServer),
m_qmlServices(qmlServices)
{
setId(AppManager::Constants::DEBUG_LAUNCHER_ID);
@@ -110,12 +109,19 @@ public:
if (usePerf) {
suppressDefaultStdOutHandling();
runControl->setProperty("PerfProcess", QVariant::fromValue(process()));
m_perfChannelProvider = new Debugger::SubChannelProvider(runControl);
addStartDependency(m_perfChannelProvider);
}
m_portsGatherer = new Debugger::DebugServerPortsGatherer(runControl);
m_portsGatherer->setUseGdbServer(useGdbServer || usePerf);
m_portsGatherer->setUseQmlServer(useQmlServer);
addStartDependency(m_portsGatherer);
if (useGdbServer) {
m_debugChannelProvider = new Debugger::SubChannelProvider(runControl);
addStartDependency(m_debugChannelProvider);
}
if (useQmlServer) {
m_qmlChannelProvider = new Debugger::SubChannelProvider(runControl);
addStartDependency(m_qmlChannelProvider);
}
setStartModifier([this, runControl] {
FilePath controller = runControl->aspectData<AppManagerControllerAspect>()->filePath;
@@ -128,30 +134,28 @@ public:
envVars = envAspect->environment.toStringList();
envVars.replaceInStrings(" ", "\\ ");
const int gdbServerPort = m_portsGatherer->gdbServer().port();
const int qmlServerPort = m_portsGatherer->qmlServer().port();
CommandLine cmd{controller};
if (!instanceId.isEmpty())
cmd.addArgs({"--instance-id", instanceId});
cmd.addArg("debug-application");
if (m_useGdbServer || m_useQmlServer) {
if (m_debugChannelProvider || m_qmlChannelProvider) {
QStringList debugArgs;
debugArgs.append(envVars.join(' '));
if (m_useGdbServer) {
debugArgs.append(QString("gdbserver :%1").arg(gdbServerPort));
if (m_debugChannelProvider) {
debugArgs.append(QString("gdbserver :%1").arg(m_debugChannelProvider->channel().port()));
}
if (m_useQmlServer) {
debugArgs.append(QString("%program% %1 %arguments%")
.arg(qmlDebugCommandLineArguments(m_qmlServices,
QString("port:%1").arg(qmlServerPort),
true)));
if (m_qmlChannelProvider) {
const QString qmlArgs =
qmlDebugCommandLineArguments(m_qmlServices,
QString("port:%1").arg(m_qmlChannelProvider->channel().port()),
true);
debugArgs.append(QString("%program% %1 %arguments%") .arg(qmlArgs));
}
cmd.addArg(debugArgs.join(' '));
}
if (m_usePerf) {
if (m_perfChannelProvider) {
const Store perfArgs = runControl->settingsData(PerfProfiler::Constants::PerfSettingsId);
const QString recordArgs = perfArgs[PerfProfiler::Constants::PerfRecordArgsId].toString();
cmd.addArg(QString("perf record %1 -o - --").arg(recordArgs));
@@ -177,15 +181,22 @@ public:
});
}
QUrl perfServer() const { return m_portsGatherer->gdbServer(); }
QUrl gdbServer() const { return m_portsGatherer->gdbServer(); }
QUrl qmlServer() const { return m_portsGatherer->qmlServer(); }
QUrl gdbServer() const
{
QTC_ASSERT(m_debugChannelProvider, return {});
return m_debugChannelProvider->channel();
}
QUrl qmlServer() const
{
QTC_ASSERT(m_qmlChannelProvider, return {});
return m_qmlChannelProvider->channel();
}
private:
Debugger::DebugServerPortsGatherer *m_portsGatherer = nullptr;
bool m_usePerf;
bool m_useGdbServer;
bool m_useQmlServer;
Debugger::SubChannelProvider *m_debugChannelProvider = nullptr;
Debugger::SubChannelProvider *m_qmlChannelProvider = nullptr;
Debugger::SubChannelProvider *m_perfChannelProvider = nullptr;
QmlDebug::QmlDebugServicesPreset m_qmlServices;
};