// Copyright (C) 2016 Denis Shienkov // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "openocdgdbserverprovider.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace Utils; namespace BareMetal::Internal { const char executableFileKeyC[] = "ExecutableFile"; const char rootScriptsDirKeyC[] = "RootScriptsDir"; const char configurationFileKeyC[] = "ConfigurationPath"; const char additionalArgumentsKeyC[] = "AdditionalArguments"; // OpenOcdGdbServerProvider OpenOcdGdbServerProvider::OpenOcdGdbServerProvider() : GdbServerProvider(Constants::GDBSERVER_OPENOCD_PROVIDER_ID) { setInitCommands(defaultInitCommands()); setResetCommands(defaultResetCommands()); setChannel("localhost", 3333); setTypeDisplayName(Tr::tr("OpenOCD")); setConfigurationWidgetCreator([this] { return new OpenOcdGdbServerProviderConfigWidget(this); }); } QString OpenOcdGdbServerProvider::defaultInitCommands() { return {"set remote hardware-breakpoint-limit 6\n" "set remote hardware-watchpoint-limit 4\n" "monitor reset halt\n" "load\n" "monitor reset halt\n"}; } QString OpenOcdGdbServerProvider::defaultResetCommands() { return {"monitor reset halt\n"}; } QString OpenOcdGdbServerProvider::channelString() const { switch (startupMode()) { case StartupOnNetwork: // Just return as "host:port" form. return GdbServerProvider::channelString(); case StartupOnPipe: { // In the pipe mode need to add quotes to each item of arguments; // otherwise running will be stuck. CommandLine cmd = command(); QStringList args = {"|", cmd.executable().toString()}; for (const QString &a : ProcessArgs::splitArgs(cmd.arguments(), HostOsInfo::hostOs())) { if (a.startsWith('\"') && a.endsWith('\"')) args << a; else args << ('\"' + a + '\"'); } return args.join(' '); } default: // wrong return {}; } } CommandLine OpenOcdGdbServerProvider::command() const { CommandLine cmd{m_executableFile}; cmd.addArg("-c"); if (startupMode() == StartupOnPipe) cmd.addArg("gdb_port pipe"); else cmd.addArg("gdb_port " + QString::number(channel().port())); if (!m_rootScriptsDir.isEmpty()) cmd.addArgs({"-s", m_rootScriptsDir.path()}); if (!m_configurationFile.isEmpty()) cmd.addArgs({"-f", m_configurationFile.path()}); if (!m_additionalArguments.isEmpty()) cmd.addArgs(m_additionalArguments, CommandLine::Raw); return cmd; } QSet OpenOcdGdbServerProvider::supportedStartupModes() const { return {StartupOnNetwork, StartupOnPipe}; } bool OpenOcdGdbServerProvider::isValid() const { if (!GdbServerProvider::isValid()) return false; const StartupMode m = startupMode(); if (m == StartupOnNetwork) { if (channel().host().isEmpty()) return false; } if (m == StartupOnNetwork || m == StartupOnPipe) { if (m_executableFile.isEmpty()) return false; } return true; } QVariantMap OpenOcdGdbServerProvider::toMap() const { QVariantMap data = GdbServerProvider::toMap(); data.insert(executableFileKeyC, m_executableFile.toSettings()); data.insert(rootScriptsDirKeyC, m_rootScriptsDir.toSettings()); data.insert(configurationFileKeyC, m_configurationFile.toSettings()); data.insert(additionalArgumentsKeyC, m_additionalArguments); return data; } bool OpenOcdGdbServerProvider::fromMap(const QVariantMap &data) { if (!GdbServerProvider::fromMap(data)) return false; m_executableFile = FilePath::fromSettings(data.value(executableFileKeyC)); m_rootScriptsDir = FilePath::fromSettings(data.value(rootScriptsDirKeyC)); m_configurationFile = FilePath::fromSettings(data.value(configurationFileKeyC)); m_additionalArguments = data.value(additionalArgumentsKeyC).toString(); return true; } bool OpenOcdGdbServerProvider::operator==(const IDebugServerProvider &other) const { if (!GdbServerProvider::operator==(other)) return false; const auto p = static_cast(&other); return m_executableFile == p->m_executableFile && m_rootScriptsDir == p->m_rootScriptsDir && m_configurationFile == p->m_configurationFile && m_additionalArguments == p->m_additionalArguments; } // OpenOcdGdbServerProviderFactory OpenOcdGdbServerProviderFactory::OpenOcdGdbServerProviderFactory() { setId(Constants::GDBSERVER_OPENOCD_PROVIDER_ID); setDisplayName(Tr::tr("OpenOCD")); setCreator([] { return new OpenOcdGdbServerProvider; }); } // OpenOcdGdbServerProviderConfigWidget OpenOcdGdbServerProviderConfigWidget::OpenOcdGdbServerProviderConfigWidget( OpenOcdGdbServerProvider *provider) : GdbServerProviderConfigWidget(provider) { Q_ASSERT(provider); m_hostWidget = new HostWidget(this); m_mainLayout->addRow(Tr::tr("Host:"), m_hostWidget); m_executableFileChooser = new Utils::PathChooser; m_executableFileChooser->setExpectedKind(Utils::PathChooser::ExistingCommand); m_executableFileChooser->setCommandVersionArguments({"--version"}); m_mainLayout->addRow(Tr::tr("Executable file:"), m_executableFileChooser); m_rootScriptsDirChooser = new Utils::PathChooser; m_rootScriptsDirChooser->setExpectedKind(Utils::PathChooser::Directory); m_mainLayout->addRow(Tr::tr("Root scripts directory:"), m_rootScriptsDirChooser); m_configurationFileChooser = new Utils::PathChooser; m_configurationFileChooser->setExpectedKind(Utils::PathChooser::File); m_configurationFileChooser->setPromptDialogFilter("*.cfg"); m_mainLayout->addRow(Tr::tr("Configuration file:"), m_configurationFileChooser); m_additionalArgumentsLineEdit = new QLineEdit(this); m_mainLayout->addRow(Tr::tr("Additional arguments:"), m_additionalArgumentsLineEdit); m_initCommandsTextEdit = new QPlainTextEdit(this); m_initCommandsTextEdit->setToolTip(defaultInitCommandsTooltip()); m_mainLayout->addRow(Tr::tr("Init commands:"), m_initCommandsTextEdit); m_resetCommandsTextEdit = new QPlainTextEdit(this); m_resetCommandsTextEdit->setToolTip(defaultResetCommandsTooltip()); m_mainLayout->addRow(Tr::tr("Reset commands:"), m_resetCommandsTextEdit); addErrorLabel(); setFromProvider(); const auto chooser = new VariableChooser(this); chooser->addSupportedWidget(m_initCommandsTextEdit); chooser->addSupportedWidget(m_resetCommandsTextEdit); connect(m_hostWidget, &HostWidget::dataChanged, this, &GdbServerProviderConfigWidget::dirty); connect(m_executableFileChooser, &Utils::PathChooser::rawPathChanged, this, &GdbServerProviderConfigWidget::dirty); connect(m_rootScriptsDirChooser, &Utils::PathChooser::rawPathChanged, this, &GdbServerProviderConfigWidget::dirty); connect(m_configurationFileChooser, &Utils::PathChooser::rawPathChanged, this, &GdbServerProviderConfigWidget::dirty); connect(m_additionalArgumentsLineEdit, &QLineEdit::textChanged, this, &GdbServerProviderConfigWidget::dirty); connect(m_initCommandsTextEdit, &QPlainTextEdit::textChanged, this, &GdbServerProviderConfigWidget::dirty); connect(m_resetCommandsTextEdit, &QPlainTextEdit::textChanged, this, &GdbServerProviderConfigWidget::dirty); connect(m_startupModeComboBox, &QComboBox::currentIndexChanged, this, &OpenOcdGdbServerProviderConfigWidget::startupModeChanged); } void OpenOcdGdbServerProviderConfigWidget::apply() { const auto p = static_cast(m_provider); Q_ASSERT(p); p->setChannel(m_hostWidget->channel()); p->m_executableFile = m_executableFileChooser->filePath(); p->m_rootScriptsDir = m_rootScriptsDirChooser->filePath(); p->m_configurationFile = m_configurationFileChooser->filePath(); p->m_additionalArguments = m_additionalArgumentsLineEdit->text(); p->setInitCommands(m_initCommandsTextEdit->toPlainText()); p->setResetCommands(m_resetCommandsTextEdit->toPlainText()); GdbServerProviderConfigWidget::apply(); } void OpenOcdGdbServerProviderConfigWidget::discard() { setFromProvider(); GdbServerProviderConfigWidget::discard(); } void OpenOcdGdbServerProviderConfigWidget::startupModeChanged() { const GdbServerProvider::StartupMode m = startupMode(); const bool isNetwork = m != GdbServerProvider::StartupOnPipe; m_hostWidget->setVisible(isNetwork); m_mainLayout->labelForField(m_hostWidget)->setVisible(isNetwork); } void OpenOcdGdbServerProviderConfigWidget::setFromProvider() { const auto p = static_cast(m_provider); Q_ASSERT(p); const QSignalBlocker blocker(this); startupModeChanged(); m_hostWidget->setChannel(p->channel()); m_executableFileChooser->setFilePath(p->m_executableFile); m_rootScriptsDirChooser->setFilePath(p->m_rootScriptsDir); m_configurationFileChooser->setFilePath(p->m_configurationFile); m_additionalArgumentsLineEdit->setText(p->m_additionalArguments); m_initCommandsTextEdit->setPlainText(p->initCommands()); m_resetCommandsTextEdit->setPlainText(p->resetCommands()); } } // BareMetal::Internal