2014-12-20 19:10:02 +00:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 Denis Shienkov <denis.shienkov@gmail.com>
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2014-12-20 19:10:02 +00:00
|
|
|
**
|
|
|
|
|
** 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
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2014-12-20 19:10:02 +00:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2014-12-20 19:10:02 +00:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "gdbserverprovider.h"
|
2019-11-04 00:51:58 +03:00
|
|
|
|
|
|
|
|
#include <baremetal/baremetaldevice.h>
|
|
|
|
|
#include <baremetal/debugserverprovidermanager.h>
|
2014-12-20 19:10:02 +00:00
|
|
|
|
|
|
|
|
#include <utils/environment.h>
|
2019-05-08 13:49:19 +03:00
|
|
|
#include <utils/qtcassert.h>
|
2014-12-20 19:10:02 +00:00
|
|
|
|
2019-05-08 13:49:19 +03:00
|
|
|
#include <QComboBox>
|
2014-12-20 19:10:02 +00:00
|
|
|
#include <QFormLayout>
|
2019-05-08 13:49:19 +03:00
|
|
|
#include <QLineEdit>
|
|
|
|
|
#include <QSpinBox>
|
2014-12-20 19:10:02 +00:00
|
|
|
|
|
|
|
|
namespace BareMetal {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
const char startupModeKeyC[] = "BareMetal.GdbServerProvider.Mode";
|
|
|
|
|
const char initCommandsKeyC[] = "BareMetal.GdbServerProvider.InitCommands";
|
|
|
|
|
const char resetCommandsKeyC[] = "BareMetal.GdbServerProvider.ResetCommands";
|
2019-05-08 12:23:07 +10:00
|
|
|
const char useExtendedRemoteKeyC[] = "BareMetal.GdbServerProvider.UseExtendedRemote";
|
2014-12-20 19:10:02 +00:00
|
|
|
|
2019-07-23 16:29:33 +02:00
|
|
|
const char hostKeySuffixC[] = ".Host";
|
|
|
|
|
const char portKeySuffixC[] = ".Port";
|
|
|
|
|
|
2019-05-08 13:49:19 +03:00
|
|
|
// GdbServerProvider
|
|
|
|
|
|
2014-12-20 19:10:02 +00:00
|
|
|
GdbServerProvider::GdbServerProvider(const QString &id)
|
2019-11-04 00:51:58 +03:00
|
|
|
: IDebugServerProvider(id)
|
2014-12-20 19:10:02 +00:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GdbServerProvider::GdbServerProvider(const GdbServerProvider &other)
|
2019-11-04 00:51:58 +03:00
|
|
|
: IDebugServerProvider(other.id())
|
2014-12-20 19:10:02 +00:00
|
|
|
, m_startupMode(other.m_startupMode)
|
|
|
|
|
, m_initCommands(other.m_initCommands)
|
|
|
|
|
, m_resetCommands(other.m_resetCommands)
|
2019-05-08 12:23:07 +10:00
|
|
|
, m_useExtendedRemote(other.useExtendedRemote())
|
2014-12-20 19:10:02 +00:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-08 12:23:07 +10:00
|
|
|
bool GdbServerProvider::useExtendedRemote() const
|
|
|
|
|
{
|
|
|
|
|
return m_useExtendedRemote;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProvider::setUseExtendedRemote(bool useExtendedRemote)
|
|
|
|
|
{
|
|
|
|
|
m_useExtendedRemote = useExtendedRemote;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-20 19:10:02 +00:00
|
|
|
QString GdbServerProvider::resetCommands() const
|
|
|
|
|
{
|
|
|
|
|
return m_resetCommands;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProvider::setResetCommands(const QString &cmds)
|
|
|
|
|
{
|
|
|
|
|
m_resetCommands = cmds;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-23 16:29:33 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-04 10:17:06 +02:00
|
|
|
Utils::CommandLine GdbServerProvider::command() const
|
2014-12-20 19:10:02 +00:00
|
|
|
{
|
2019-05-08 14:42:54 +03:00
|
|
|
return {};
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-04 00:51:58 +03:00
|
|
|
bool GdbServerProvider::operator==(const IDebugServerProvider &other) const
|
2014-12-20 19:10:02 +00:00
|
|
|
{
|
2019-11-04 00:51:58 +03:00
|
|
|
if (!IDebugServerProvider::operator==(other))
|
|
|
|
|
return false;
|
2014-12-20 19:10:02 +00:00
|
|
|
|
2019-11-04 00:51:58 +03:00
|
|
|
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;
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
2019-07-23 16:29:33 +02:00
|
|
|
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());
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-20 19:10:02 +00:00
|
|
|
QVariantMap GdbServerProvider::toMap() const
|
|
|
|
|
{
|
2019-11-04 00:51:58 +03:00
|
|
|
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;
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GdbServerProvider::isValid() const
|
|
|
|
|
{
|
2019-07-23 16:29:33 +02:00
|
|
|
return !channelString().isEmpty();
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GdbServerProvider::canStartupMode(StartupMode m) const
|
|
|
|
|
{
|
|
|
|
|
return m == NoStartup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GdbServerProvider::fromMap(const QVariantMap &data)
|
|
|
|
|
{
|
2019-11-04 00:51:58 +03:00
|
|
|
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();
|
2019-07-23 16:29:33 +02:00
|
|
|
m_channel.setHost(data.value(m_settingsBase + hostKeySuffixC).toString());
|
|
|
|
|
m_channel.setPort(data.value(m_settingsBase + portKeySuffixC).toInt());
|
2014-12-20 19:10:02 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-23 16:29:33 +02:00
|
|
|
void GdbServerProvider::setSettingsKeyBase(const QString &settingsBase)
|
|
|
|
|
{
|
|
|
|
|
m_settingsBase = settingsBase;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-08 13:49:19 +03:00
|
|
|
// GdbServerProviderConfigWidget
|
|
|
|
|
|
2014-12-20 19:10:02 +00:00
|
|
|
GdbServerProviderConfigWidget::GdbServerProviderConfigWidget(
|
|
|
|
|
GdbServerProvider *provider)
|
2019-11-04 00:51:58 +03:00
|
|
|
: IDebugServerProviderConfigWidget(provider)
|
2014-12-20 19:10:02 +00:00
|
|
|
{
|
|
|
|
|
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();
|
|
|
|
|
|
2015-11-29 18:58:42 +03:00
|
|
|
connect(m_startupModeComboBox,
|
2019-02-26 09:40:49 +01:00
|
|
|
QOverload<int>::of(&QComboBox::currentIndexChanged),
|
2015-11-29 18:58:42 +03:00
|
|
|
this, &GdbServerProviderConfigWidget::dirty);
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderConfigWidget::apply()
|
|
|
|
|
{
|
2019-11-04 00:51:58 +03:00
|
|
|
static_cast<GdbServerProvider *>(m_provider)->setStartupMode(startupMode());
|
|
|
|
|
IDebugServerProviderConfigWidget::apply();
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderConfigWidget::discard()
|
|
|
|
|
{
|
2019-11-04 00:51:58 +03:00
|
|
|
setFromProvider();
|
|
|
|
|
IDebugServerProviderConfigWidget::discard();
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
2019-11-04 00:51:58 +03:00
|
|
|
if (!static_cast<GdbServerProvider *>(m_provider)->canStartupMode(m))
|
2014-12-20 19:10:02 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
const int idx = m_startupModeComboBox->count();
|
|
|
|
|
m_startupModeComboBox->insertItem(
|
|
|
|
|
idx,
|
|
|
|
|
(m == GdbServerProvider::NoStartup)
|
2015-03-16 14:53:19 +01:00
|
|
|
? tr("No Startup")
|
2014-12-20 19:10:02 +00:00
|
|
|
: ((m == GdbServerProvider::StartupOnNetwork)
|
2015-03-16 14:53:19 +01:00
|
|
|
? tr("Startup in TCP/IP Mode")
|
|
|
|
|
: tr("Startup in Pipe Mode")),
|
2014-12-20 19:10:02 +00:00
|
|
|
m);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbServerProviderConfigWidget::setFromProvider()
|
|
|
|
|
{
|
2019-11-04 00:51:58 +03:00
|
|
|
setStartupMode(static_cast<GdbServerProvider *>(m_provider)->startupMode());
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbServerProviderConfigWidget::defaultInitCommandsTooltip()
|
|
|
|
|
{
|
|
|
|
|
return QCoreApplication::translate("BareMetal",
|
2015-03-23 14:17:57 +01:00
|
|
|
"Enter GDB commands to reset the board "
|
2014-12-20 19:10:02 +00:00
|
|
|
"and to write the nonvolatile memory.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString GdbServerProviderConfigWidget::defaultResetCommandsTooltip()
|
|
|
|
|
{
|
|
|
|
|
return QCoreApplication::translate("BareMetal",
|
2015-03-16 12:38:31 +01:00
|
|
|
"Enter GDB commands to reset the hardware. "
|
2015-03-23 14:17:57 +01:00
|
|
|
"The MCU should be halted after these commands.");
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-04 00:51:58 +03:00
|
|
|
// 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, {}); });
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-08 13:49:19 +03:00
|
|
|
// HostWidget
|
|
|
|
|
|
2014-12-20 19:10:02 +00:00
|
|
|
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);
|
2015-02-09 23:04:12 +02:00
|
|
|
m_portSpinBox->setRange(0, 65535);
|
2014-12-20 19:10:02 +00:00
|
|
|
m_portSpinBox->setToolTip(tr("Enter TCP/IP port which will be listened by "
|
|
|
|
|
"the GDB server provider."));
|
2019-05-08 13:49:19 +03:00
|
|
|
const auto layout = new QHBoxLayout(this);
|
2014-12-20 19:10:02 +00:00
|
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
layout->addWidget(m_hostLineEdit);
|
|
|
|
|
layout->addWidget(m_portSpinBox);
|
|
|
|
|
|
2015-11-29 18:58:42 +03:00
|
|
|
connect(m_hostLineEdit, &QLineEdit::textChanged,
|
|
|
|
|
this, &HostWidget::dataChanged);
|
2019-02-26 09:40:49 +01:00
|
|
|
connect(m_portSpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
|
2015-11-29 18:58:42 +03:00
|
|
|
this, &HostWidget::dataChanged);
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
2019-07-23 16:29:33 +02:00
|
|
|
void HostWidget::setChannel(const QUrl &channel)
|
2014-12-20 19:10:02 +00:00
|
|
|
{
|
2019-05-08 16:18:16 +03:00
|
|
|
const QSignalBlocker blocker(this);
|
2019-07-23 16:29:33 +02:00
|
|
|
m_hostLineEdit->setText(channel.host());
|
|
|
|
|
m_portSpinBox->setValue(channel.port());
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
2019-07-23 16:29:33 +02:00
|
|
|
QUrl HostWidget::channel() const
|
2014-12-20 19:10:02 +00:00
|
|
|
{
|
2019-07-23 16:29:33 +02:00
|
|
|
QUrl url;
|
|
|
|
|
url.setHost(m_hostLineEdit->text());
|
|
|
|
|
url.setPort(m_portSpinBox->value());
|
|
|
|
|
return url;
|
2014-12-20 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace BareMetal
|