From 8f48a30fa35c2a6cbc292acc6b0b0bb485db97bc Mon Sep 17 00:00:00 2001 From: Nav Date: Sat, 10 Dec 2022 14:54:38 +0000 Subject: [PATCH] Command option extraction for GDB monitor commands --- src/DebugServer/CMakeLists.txt | 2 +- .../Gdb/CommandPackets/GenerateSvd.cpp | 2 +- .../Gdb/CommandPackets/Monitor.cpp | 78 +++++++++++++++++-- .../Gdb/CommandPackets/Monitor.hpp | 21 +++++ 4 files changed, 94 insertions(+), 9 deletions(-) diff --git a/src/DebugServer/CMakeLists.txt b/src/DebugServer/CMakeLists.txt index c7fac4ab..d13ae1e8 100755 --- a/src/DebugServer/CMakeLists.txt +++ b/src/DebugServer/CMakeLists.txt @@ -8,6 +8,7 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/GdbDebugServerConfig.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/Connection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/DebugSession.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/ResponsePackets/SupportedFeaturesResponse.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/CommandPackets/CommandPacket.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/CommandPackets/SupportedFeaturesQuery.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/CommandPackets/ReadRegisters.cpp @@ -24,7 +25,6 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/CommandPackets/BloomVersionMachine.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/CommandPackets/GenerateSvd.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/CommandPackets/Detach.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/ResponsePackets/SupportedFeaturesResponse.cpp # AVR GDB RSP Server ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/AvrGdbRsp.cpp diff --git a/src/DebugServer/Gdb/CommandPackets/GenerateSvd.cpp b/src/DebugServer/Gdb/CommandPackets/GenerateSvd.cpp index e7613d37..51f3b311 100644 --- a/src/DebugServer/Gdb/CommandPackets/GenerateSvd.cpp +++ b/src/DebugServer/Gdb/CommandPackets/GenerateSvd.cpp @@ -23,7 +23,7 @@ namespace Bloom::DebugServer::Gdb::CommandPackets GenerateSvd::GenerateSvd(Monitor&& monitorPacket) : Monitor(std::move(monitorPacket)) - , sendOutput(this->command.find("--out") != std::string::npos) + , sendOutput(this->commandOptions.contains("out")) {} void GenerateSvd::handle(DebugSession& debugSession, TargetControllerConsole&) { diff --git a/src/DebugServer/Gdb/CommandPackets/Monitor.cpp b/src/DebugServer/Gdb/CommandPackets/Monitor.cpp index 44485814..676e7a47 100644 --- a/src/DebugServer/Gdb/CommandPackets/Monitor.cpp +++ b/src/DebugServer/Gdb/CommandPackets/Monitor.cpp @@ -13,18 +13,82 @@ namespace Bloom::DebugServer::Gdb::CommandPackets Monitor::Monitor(const RawPacket& rawPacket) : CommandPacket(rawPacket) { - if (this->data.size() > 6) { - const auto decodedCommand = Packet::hexToData( - std::string(this->data.begin() + 6, this->data.end()) - ); - - this->command = std::string(decodedCommand.begin(), decodedCommand.end()); - this->command.erase(this->command.find_last_not_of(" ") + 1); + if (this->data.size() <= 6) { + return; } + + const auto decodedCommand = Packet::hexToData( + std::string(this->data.begin() + 6, this->data.end()) + ); + + this->command = std::string(decodedCommand.begin(), decodedCommand.end()); + this->command.erase(this->command.find_last_not_of(" ") + 1); + + this->commandOptions = this->extractCommandOptions(this->command); } void Monitor::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) { Logger::error("Unknown custom GDB command (\"" + this->command + "\") received."); debugSession.connection.writePacket(EmptyResponsePacket()); } + + std::map> Monitor::extractCommandOptions(const std::string& command) { + auto output = std::map>(); + + for (std::string::size_type cmdIndex = 1; cmdIndex < command.size(); ++cmdIndex) { + const auto cmdChar = command.at(cmdIndex); + + if (cmdChar == '-') { + if (command.at(cmdIndex - 1) != '-') { + continue; + } + + auto option = std::string(); + auto optionValue = std::optional(); + + bool quoted = false; + + auto optIndex = std::string::size_type(0); + for (optIndex = cmdIndex + 1; optIndex < command.size(); ++optIndex) { + const auto optChar = command.at(optIndex); + + if (!option.empty() && ((!quoted && optChar == ' ') || (quoted && optChar == '"'))) { + output.insert(std::pair(option, optionValue)); + + option.clear(); + optionValue.reset(); + quoted = false; + + cmdIndex = optIndex; + break; + } + + if (optionValue.has_value()) { + if (optChar == '"' && !quoted && optionValue->empty()) { + quoted = true; + continue; + } + + optionValue->push_back(optChar); + continue; + } + + if (optChar == '=') { + optionValue = std::string(); + continue; + } + + option.push_back(optChar); + continue; + } + + if (!option.empty()) { + output.insert(std::pair(option, optionValue)); + cmdIndex = optIndex; + } + } + } + + return output; + } } diff --git a/src/DebugServer/Gdb/CommandPackets/Monitor.hpp b/src/DebugServer/Gdb/CommandPackets/Monitor.hpp index 36e757d8..0de0811f 100644 --- a/src/DebugServer/Gdb/CommandPackets/Monitor.hpp +++ b/src/DebugServer/Gdb/CommandPackets/Monitor.hpp @@ -1,6 +1,9 @@ #pragma once #include +#include +#include +#include #include "CommandPacket.hpp" @@ -17,11 +20,29 @@ namespace Bloom::DebugServer::Gdb::CommandPackets */ std::string command; + /** + * A mapping of any command options included in this->command. A command option must begin with "--" and + * can optionally have a value. + * + * The key of this map is the option name. The map value is the option value, or std::nullopt if no value was + * provided. + */ + std::map> commandOptions; + explicit Monitor(const RawPacket& rawPacket); void handle( DebugSession& debugSession, TargetController::TargetControllerConsole& targetControllerConsole ) override; + + private: + /** + * Extracts command options from a command string. + * + * @param command + * @return + */ + std::map> extractCommandOptions(const std::string& command); }; }