// Copyright (C) 2016 Denis Shienkov // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "gdbserverprovider.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace Debugger; using namespace ProjectExplorer; using namespace Utils; namespace BareMetal::Internal { const char startupModeKeyC[] = "Mode"; const char peripheralDescriptionFileKeyC[] = "PeripheralDescriptionFile"; const char initCommandsKeyC[] = "InitCommands"; const char resetCommandsKeyC[] = "ResetCommands"; const char useExtendedRemoteKeyC[] = "UseExtendedRemote"; // GdbServerProvider GdbServerProvider::GdbServerProvider(const QString &id) : IDebugServerProvider(id) { setEngineType(Debugger::GdbEngineType); } GdbServerProvider::GdbServerProvider(const GdbServerProvider &other) : IDebugServerProvider(other.id()) , m_startupMode(other.m_startupMode) , m_peripheralDescriptionFile(other.m_peripheralDescriptionFile) , m_initCommands(other.m_initCommands) , m_resetCommands(other.m_resetCommands) , m_useExtendedRemote(other.useExtendedRemote()) { setEngineType(Debugger::GdbEngineType); } GdbServerProvider::StartupMode GdbServerProvider::startupMode() const { return m_startupMode; } FilePath GdbServerProvider::peripheralDescriptionFile() const { return m_peripheralDescriptionFile; } void GdbServerProvider::setStartupMode(StartupMode m) { m_startupMode = m; } void GdbServerProvider::setPeripheralDescriptionFile(const FilePath &file) { m_peripheralDescriptionFile = file; } 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; } Utils::CommandLine GdbServerProvider::command() const { return {}; } bool GdbServerProvider::operator==(const IDebugServerProvider &other) const { if (!IDebugServerProvider::operator==(other)) return false; const auto p = static_cast(&other); return m_startupMode == p->m_startupMode && m_peripheralDescriptionFile == p->m_peripheralDescriptionFile && m_initCommands == p->m_initCommands && m_resetCommands == p->m_resetCommands && m_useExtendedRemote == p->m_useExtendedRemote; } QVariantMap GdbServerProvider::toMap() const { QVariantMap data = IDebugServerProvider::toMap(); data.insert(startupModeKeyC, m_startupMode); data.insert(peripheralDescriptionFileKeyC, m_peripheralDescriptionFile.toVariant()); data.insert(initCommandsKeyC, m_initCommands); data.insert(resetCommandsKeyC, m_resetCommands); data.insert(useExtendedRemoteKeyC, m_useExtendedRemote); return data; } bool GdbServerProvider::isValid() const { return !channelString().isEmpty(); } bool GdbServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMessage) const { QTC_ASSERT(runTool, return false); const RunControl *runControl = runTool->runControl(); const auto exeAspect = runControl->aspect(); QTC_ASSERT(exeAspect, return false); const FilePath bin = FilePath::fromString(exeAspect->executable.path()); if (bin.isEmpty()) { errorMessage = Tr::tr("Cannot debug: Local executable is not set."); return false; } if (!bin.exists()) { errorMessage = Tr::tr("Cannot debug: Could not find executable for \"%1\".") .arg(bin.toString()); return false; } Runnable inferior; inferior.command.setExecutable(bin); if (const auto argAspect = runControl->aspect()) inferior.command.setArguments(argAspect->arguments); runTool->setInferior(inferior); runTool->setSymbolFile(bin); runTool->setStartMode(AttachToRemoteServer); runTool->setCommandsAfterConnect(initCommands()); // .. and here? runTool->setCommandsForReset(resetCommands()); runTool->setRemoteChannel(channelString()); runTool->setUseContinueInsteadOfRun(true); runTool->setUseExtendedRemote(useExtendedRemote()); runTool->runParameters().peripheralDescriptionFile = m_peripheralDescriptionFile; return true; } RunWorker *GdbServerProvider::targetRunner(RunControl *runControl) const { if (m_startupMode != GdbServerProvider::StartupOnNetwork) return nullptr; // Command arguments are in host OS style as the bare metal's GDB servers are launched // on the host, not on that target. return new GdbServerProviderRunner(runControl, command()); } bool GdbServerProvider::fromMap(const QVariantMap &data) { if (!IDebugServerProvider::fromMap(data)) return false; m_startupMode = static_cast(data.value(startupModeKeyC).toInt()); m_peripheralDescriptionFile = FilePath::fromVariant(data.value(peripheralDescriptionFileKeyC)); m_initCommands = data.value(initCommandsKeyC).toString(); m_resetCommands = data.value(resetCommandsKeyC).toString(); m_useExtendedRemote = data.value(useExtendedRemoteKeyC).toBool(); return true; } // GdbServerProviderConfigWidget GdbServerProviderConfigWidget::GdbServerProviderConfigWidget( GdbServerProvider *provider) : IDebugServerProviderConfigWidget(provider) { m_startupModeComboBox = new QComboBox(this); m_startupModeComboBox->setToolTip(Tr::tr("Choose the desired startup mode " "of the GDB server provider.")); m_mainLayout->addRow(Tr::tr("Startup mode:"), m_startupModeComboBox); m_peripheralDescriptionFileChooser = new PathChooser(this); m_peripheralDescriptionFileChooser->setExpectedKind(PathChooser::File); m_peripheralDescriptionFileChooser->setPromptDialogFilter( Tr::tr("Peripheral description files (*.svd)")); m_peripheralDescriptionFileChooser->setPromptDialogTitle( Tr::tr("Select Peripheral Description File")); m_mainLayout->addRow(Tr::tr("Peripheral description file:"), m_peripheralDescriptionFileChooser); populateStartupModes(); setFromProvider(); connect(m_startupModeComboBox, &QComboBox::currentIndexChanged, this, &GdbServerProviderConfigWidget::dirty); connect(m_peripheralDescriptionFileChooser, &PathChooser::textChanged, this, &GdbServerProviderConfigWidget::dirty); } void GdbServerProviderConfigWidget::apply() { const auto p = static_cast(m_provider); p->setStartupMode(startupMode()); p->setPeripheralDescriptionFile(peripheralDescriptionFile()); IDebugServerProviderConfigWidget::apply(); } void GdbServerProviderConfigWidget::discard() { setFromProvider(); IDebugServerProviderConfigWidget::discard(); } GdbServerProvider::StartupMode GdbServerProviderConfigWidget::startupModeFromIndex( int idx) const { return static_cast( 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; } } } static QString startupModeName(GdbServerProvider::StartupMode m) { switch (m) { case GdbServerProvider::StartupOnNetwork: return Tr::tr("Startup in TCP/IP Mode"); case GdbServerProvider::StartupOnPipe: return Tr::tr("Startup in Pipe Mode"); default: return {}; } } void GdbServerProviderConfigWidget::populateStartupModes() { const QSet modes = static_cast( m_provider)->supportedStartupModes(); for (const auto mode : modes) m_startupModeComboBox->addItem(startupModeName(mode), mode); } FilePath GdbServerProviderConfigWidget::peripheralDescriptionFile() const { return m_peripheralDescriptionFileChooser->filePath(); } void GdbServerProviderConfigWidget::setPeripheralDescriptionFile(const FilePath &file) { m_peripheralDescriptionFileChooser->setFilePath(file); } void GdbServerProviderConfigWidget::setFromProvider() { const auto p = static_cast(m_provider); setStartupMode(p->startupMode()); setPeripheralDescriptionFile(p->peripheralDescriptionFile()); } QString GdbServerProviderConfigWidget::defaultInitCommandsTooltip() { return Tr::tr("Enter GDB commands to reset the board " "and to write the nonvolatile memory."); } QString GdbServerProviderConfigWidget::defaultResetCommandsTooltip() { return Tr::tr("Enter GDB commands to reset the hardware. " "The MCU should be halted after these commands."); } // GdbServerProviderRunner GdbServerProviderRunner::GdbServerProviderRunner(ProjectExplorer::RunControl *runControl, const CommandLine &commandLine) : SimpleTargetRunner(runControl) { setId("BareMetalGdbServer"); // Baremetal's GDB servers are launched on the host, not on the target. setStartModifier([this, commandLine] { setCommandLine(commandLine); forceRunOnHost(); }); } } // BareMetal::Internal