Files
qt-creator/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp
Denis Shienkov 4828aa7244 BareMetal: Minimize dependency from GDB engine
The problem is that this plugin was originally developed
only for working with the GDB debugging engine. This hard
dependency penetrates to all plugin logic, that excludes an
easy addition of other types of a debugger engines.

This patch tries to minimize the GDB dependency and improves
code a bit in the following way:

 * A code that belongs to the GDB engine moved to the separate
debugservers/gdb directory.
 * A classes having a common functionality are renamed with
'Debug' suffixes instead of 'Gdb' suffixes.
 * Introduced a new interface IDebugServerProvider{Factory|ConfigWidget}
whih are used as a base for all derived debug servers
providers (e.g. for the OpenOCD, STLink and etc).
 * The IDebugServerProvider interface has a new virtual
engineType() method to show a supported debugger engine by
a specific debugger server provider. This method is used in
BareMetalDebugSupport class to detect a provider engine
for an additional initialization (which depends on an used
debugger engine).
 * The IDebugServerProvider interface has a new virtual hasProcess()
method. E.g. this is required for a future debug server providers
which has not a remote processes. In this case the
BareMetalDevice::canCreateProcess() will report about that in
a right way.

Thus, this approach allowed us to preserve a previous behavior
of an already implemented GDB providers. Also it makes possible
to add a new providers in a future with a minimized costs.

Change-Id: I1be84b9178d4aa78c3ef5108a9e6b381e245f36f
Reviewed-by: hjk <hjk@qt.io>
2019-11-04 10:55:46 +00:00

332 lines
10 KiB
C++

/****************************************************************************
**
** Copyright (C) 2016 Denis Shienkov <denis.shienkov@gmail.com>
** 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 "gdbserverprovider.h"
#include <baremetal/baremetaldevice.h>
#include <baremetal/debugserverprovidermanager.h>
#include <utils/environment.h>
#include <utils/qtcassert.h>
#include <QComboBox>
#include <QFormLayout>
#include <QLineEdit>
#include <QSpinBox>
namespace BareMetal {
namespace Internal {
const char startupModeKeyC[] = "BareMetal.GdbServerProvider.Mode";
const char initCommandsKeyC[] = "BareMetal.GdbServerProvider.InitCommands";
const char resetCommandsKeyC[] = "BareMetal.GdbServerProvider.ResetCommands";
const char useExtendedRemoteKeyC[] = "BareMetal.GdbServerProvider.UseExtendedRemote";
const char hostKeySuffixC[] = ".Host";
const char portKeySuffixC[] = ".Port";
// GdbServerProvider
GdbServerProvider::GdbServerProvider(const QString &id)
: IDebugServerProvider(id)
{
}
GdbServerProvider::GdbServerProvider(const GdbServerProvider &other)
: IDebugServerProvider(other.id())
, m_startupMode(other.m_startupMode)
, m_initCommands(other.m_initCommands)
, m_resetCommands(other.m_resetCommands)
, m_useExtendedRemote(other.useExtendedRemote())
{
}
GdbServerProvider::StartupMode GdbServerProvider::startupMode() const
{
return m_startupMode;
}
void GdbServerProvider::setStartupMode(StartupMode m)
{
m_startupMode = m;
}
QString GdbServerProvider::initCommands() const
{
return m_initCommands;
}
void GdbServerProvider::setInitCommands(const QString &cmds)
{
m_initCommands = cmds;
}
bool GdbServerProvider::useExtendedRemote() const
{
return m_useExtendedRemote;
}
void GdbServerProvider::setUseExtendedRemote(bool useExtendedRemote)
{
m_useExtendedRemote = useExtendedRemote;
}
QString GdbServerProvider::resetCommands() const
{
return m_resetCommands;
}
void GdbServerProvider::setResetCommands(const QString &cmds)
{
m_resetCommands = cmds;
}
void GdbServerProvider::setChannel(const QUrl &channel)
{
m_channel = channel;
}
void GdbServerProvider::setDefaultChannel(const QString &host, int port)
{
m_channel.setHost(host);
m_channel.setPort(port);
}
QUrl GdbServerProvider::channel() const
{
return m_channel;
}
Utils::CommandLine GdbServerProvider::command() const
{
return {};
}
bool GdbServerProvider::operator==(const IDebugServerProvider &other) const
{
if (!IDebugServerProvider::operator==(other))
return false;
const auto p = static_cast<const GdbServerProvider *>(&other);
return m_channel == p->m_channel
&& m_startupMode == p->m_startupMode
&& m_initCommands == p->m_initCommands
&& m_resetCommands == p->m_resetCommands
&& m_useExtendedRemote == p->m_useExtendedRemote;
}
QString GdbServerProvider::channelString() const
{
// Just return as "host:port" form.
if (m_channel.port() <= 0)
return m_channel.host();
return m_channel.host() + ':' + QString::number(m_channel.port());
}
QVariantMap GdbServerProvider::toMap() const
{
QVariantMap data = IDebugServerProvider::toMap();
data.insert(startupModeKeyC, m_startupMode);
data.insert(initCommandsKeyC, m_initCommands);
data.insert(resetCommandsKeyC, m_resetCommands);
data.insert(useExtendedRemoteKeyC, m_useExtendedRemote);
data.insert(m_settingsBase + hostKeySuffixC, m_channel.host());
data.insert(m_settingsBase + portKeySuffixC, m_channel.port());
return data;
}
bool GdbServerProvider::isValid() const
{
return !channelString().isEmpty();
}
bool GdbServerProvider::canStartupMode(StartupMode m) const
{
return m == NoStartup;
}
bool GdbServerProvider::fromMap(const QVariantMap &data)
{
if (!IDebugServerProvider::fromMap(data))
return false;
m_startupMode = static_cast<StartupMode>(data.value(startupModeKeyC).toInt());
m_initCommands = data.value(initCommandsKeyC).toString();
m_resetCommands = data.value(resetCommandsKeyC).toString();
m_useExtendedRemote = data.value(useExtendedRemoteKeyC).toBool();
m_channel.setHost(data.value(m_settingsBase + hostKeySuffixC).toString());
m_channel.setPort(data.value(m_settingsBase + portKeySuffixC).toInt());
return true;
}
void GdbServerProvider::setSettingsKeyBase(const QString &settingsBase)
{
m_settingsBase = settingsBase;
}
// GdbServerProviderConfigWidget
GdbServerProviderConfigWidget::GdbServerProviderConfigWidget(
GdbServerProvider *provider)
: IDebugServerProviderConfigWidget(provider)
{
m_startupModeComboBox = new QComboBox(this);
m_startupModeComboBox->setToolTip(tr("Choose the desired startup mode "
"of the GDB server provider."));
m_mainLayout->addRow(tr("Startup mode:"), m_startupModeComboBox);
populateStartupModes();
setFromProvider();
connect(m_startupModeComboBox,
QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &GdbServerProviderConfigWidget::dirty);
}
void GdbServerProviderConfigWidget::apply()
{
static_cast<GdbServerProvider *>(m_provider)->setStartupMode(startupMode());
IDebugServerProviderConfigWidget::apply();
}
void GdbServerProviderConfigWidget::discard()
{
setFromProvider();
IDebugServerProviderConfigWidget::discard();
}
GdbServerProvider::StartupMode GdbServerProviderConfigWidget::startupModeFromIndex(
int idx) const
{
return static_cast<GdbServerProvider::StartupMode>(
m_startupModeComboBox->itemData(idx).toInt());
}
GdbServerProvider::StartupMode GdbServerProviderConfigWidget::startupMode() const
{
const int idx = m_startupModeComboBox->currentIndex();
return startupModeFromIndex(idx);
}
void GdbServerProviderConfigWidget::setStartupMode(GdbServerProvider::StartupMode m)
{
for (int idx = 0; idx < m_startupModeComboBox->count(); ++idx) {
if (m == startupModeFromIndex(idx)) {
m_startupModeComboBox->setCurrentIndex(idx);
break;
}
}
}
void GdbServerProviderConfigWidget::populateStartupModes()
{
for (int i = 0; i < GdbServerProvider::StartupModesCount; ++i) {
const auto m = static_cast<GdbServerProvider::StartupMode>(i);
if (!static_cast<GdbServerProvider *>(m_provider)->canStartupMode(m))
continue;
const int idx = m_startupModeComboBox->count();
m_startupModeComboBox->insertItem(
idx,
(m == GdbServerProvider::NoStartup)
? tr("No Startup")
: ((m == GdbServerProvider::StartupOnNetwork)
? tr("Startup in TCP/IP Mode")
: tr("Startup in Pipe Mode")),
m);
}
}
void GdbServerProviderConfigWidget::setFromProvider()
{
setStartupMode(static_cast<GdbServerProvider *>(m_provider)->startupMode());
}
QString GdbServerProviderConfigWidget::defaultInitCommandsTooltip()
{
return QCoreApplication::translate("BareMetal",
"Enter GDB commands to reset the board "
"and to write the nonvolatile memory.");
}
QString GdbServerProviderConfigWidget::defaultResetCommandsTooltip()
{
return QCoreApplication::translate("BareMetal",
"Enter GDB commands to reset the hardware. "
"The MCU should be halted after these commands.");
}
// GdbServerProviderRunner
GdbServerProviderRunner::GdbServerProviderRunner(ProjectExplorer::RunControl *runControl,
const ProjectExplorer::Runnable &runnable)
: SimpleTargetRunner(runControl)
{
setId("BareMetalGdbServer");
// Baremetal's GDB servers are launched on the host, not on the target.
setStarter([this, runnable] { doStart(runnable, {}); });
}
// HostWidget
HostWidget::HostWidget(QWidget *parent)
: QWidget(parent)
{
m_hostLineEdit = new QLineEdit(this);
m_hostLineEdit->setToolTip(tr("Enter TCP/IP hostname of the GDB server provider, "
"like \"localhost\" or \"192.0.2.1\"."));
m_portSpinBox = new QSpinBox(this);
m_portSpinBox->setRange(0, 65535);
m_portSpinBox->setToolTip(tr("Enter TCP/IP port which will be listened by "
"the GDB server provider."));
const auto layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_hostLineEdit);
layout->addWidget(m_portSpinBox);
connect(m_hostLineEdit, &QLineEdit::textChanged,
this, &HostWidget::dataChanged);
connect(m_portSpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
this, &HostWidget::dataChanged);
}
void HostWidget::setChannel(const QUrl &channel)
{
const QSignalBlocker blocker(this);
m_hostLineEdit->setText(channel.host());
m_portSpinBox->setValue(channel.port());
}
QUrl HostWidget::channel() const
{
QUrl url;
url.setHost(m_hostLineEdit->text());
url.setPort(m_portSpinBox->value());
return url;
}
} // namespace Internal
} // namespace BareMetal