Replaced commandOptions member with commandArguments in the GDB Monitor command base class

Updated the `eeprom fill` monitor command to take the fill value from the third command argument.
Also updated help text
This commit is contained in:
Nav
2024-08-24 20:11:30 +01:00
parent 34ca7d4289
commit 34b26c3d06
5 changed files with 56 additions and 94 deletions

View File

@@ -2,6 +2,7 @@
#include <QByteArray>
#include <algorithm>
#include <stdexcept>
#include "src/DebugServer/Gdb/ResponsePackets/ResponsePacket.hpp"
#include "src/DebugServer/Gdb/ResponsePackets/ErrorResponsePacket.hpp"
@@ -26,12 +27,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
: Monitor(std::move(monitorPacket))
, eepromAddressSpaceDescriptor(gdbTargetDescriptor.eepromAddressSpaceDescriptor)
, eepromMemorySegmentDescriptor(gdbTargetDescriptor.eepromMemorySegmentDescriptor)
{
const auto fillValueOptionIt = this->commandOptions.find("value");
if (fillValueOptionIt != this->commandOptions.end() && fillValueOptionIt->second.has_value()) {
this->fillValue = Services::StringService::dataFromHex(*(fillValueOptionIt->second));
}
}
{}
void EepromFill::handle(
Gdb::DebugSession& debugSession,
@@ -42,13 +38,14 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
Logger::info("Handling EepromFill packet");
try {
const auto eepromSize = this->eepromMemorySegmentDescriptor.size();
const auto fillValueSize = this->fillValue.size();
if (fillValueSize == 0) {
if (this->commandArguments.size() < 3 || this->commandArguments[2].empty()) {
throw InvalidCommandOption{"Fill value required"};
}
const auto eepromSize = this->eepromMemorySegmentDescriptor.size();
const auto& fillValue = Services::StringService::dataFromHex(this->commandArguments[2]);
const auto fillValueSize = fillValue.size();
if (fillValueSize > eepromSize) {
throw InvalidCommandOption{
"Fill value size (" + std::to_string(fillValueSize) + " bytes) exceeds EEPROM size ("
@@ -68,12 +65,12 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
auto data = Targets::TargetMemoryBuffer{};
data.reserve(eepromSize);
// Repeat this->fillValue until we've filled `data`
// Repeat fillValue until we've filled `data`
while (data.size() < eepromSize) {
data.insert(
data.end(),
this->fillValue.begin(),
this->fillValue.begin() + static_cast<std::int32_t>(
fillValue.begin(),
fillValue.begin() + static_cast<std::int32_t>(
std::min(fillValueSize, (eepromSize - data.size()))
)
);
@@ -94,11 +91,15 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
)});
} catch (const InvalidCommandOption& exception) {
Logger::error(exception.getMessage());
debugSession.connection.writePacket(
ResponsePacket{Services::StringService::toHex(exception.getMessage() + "\n")}
);
} catch (const std::invalid_argument& exception) {
debugSession.connection.writePacket(
ResponsePacket{Services::StringService::toHex("Invalid fill value\n")}
);
} catch (const Exception& exception) {
Logger::error("Failed to fill EEPROM - " + exception.getMessage());
debugSession.connection.writePacket(ErrorResponsePacket{});

View File

@@ -30,8 +30,5 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
const Targets::TargetDescriptor& targetDescriptor,
Services::TargetControllerService& targetControllerService
) override;
private:
Targets::TargetMemoryBuffer fillValue;
};
}

View File

@@ -25,7 +25,7 @@ namespace DebugServer::Gdb::CommandPackets
this->command = std::string{decodedCommand.begin(), decodedCommand.end()};
this->command.erase(this->command.find_last_not_of(" ") + 1);
this->commandOptions = this->extractCommandOptions(this->command);
this->commandArguments = Monitor::extractCommandArguments(this->command);
}
void Monitor::handle(
@@ -38,61 +38,39 @@ namespace DebugServer::Gdb::CommandPackets
debugSession.connection.writePacket(EmptyResponsePacket{});
}
std::map<std::string, std::optional<std::string>> Monitor::extractCommandOptions(const std::string& command) {
auto output = std::map<std::string, std::optional<std::string>>{};
std::vector<std::string> Monitor::extractCommandArguments(const std::string& command) {
auto output = std::vector<std::string>{};
for (std::string::size_type cmdIndex = 1; cmdIndex < command.size(); ++cmdIndex) {
const auto cmdChar = command.at(cmdIndex);
auto quoteEnabled = false;
auto argument = std::string{};
if (cmdChar == '-') {
if (command.at(cmdIndex - 1) != '-') {
continue;
const auto commit = [&output, &argument] () {
output.emplace_back(std::move(argument));
argument.clear();
};
for (auto i = std::string::size_type{0}; i < command.size(); ++i) {
const auto cmdChar = command.at(i);
if (cmdChar == '"') {
if (quoteEnabled) {
commit();
}
auto option = std::string{};
auto optionValue = std::optional<std::string>{};
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.emplace(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.emplace(option, optionValue);
cmdIndex = optIndex;
}
quoteEnabled = !quoteEnabled;
continue;
}
if (!quoteEnabled && cmdChar == ' ') {
commit();
continue;
}
argument.push_back(cmdChar);
}
if (!argument.empty()) {
commit();
}
return output;

View File

@@ -2,8 +2,7 @@
#include <cstdint>
#include <string>
#include <map>
#include <optional>
#include <vector>
#include "CommandPacket.hpp"
@@ -20,14 +19,7 @@ namespace 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<std::string, std::optional<std::string>> commandOptions;
std::vector<std::string> commandArguments;
explicit Monitor(const RawPacket& rawPacket);
@@ -39,12 +31,6 @@ namespace DebugServer::Gdb::CommandPackets
) override;
private:
/**
* Extracts command options from a command string.
*
* @param command
* @return
*/
std::map<std::string, std::optional<std::string>> extractCommandOptions(const std::string& command);
static std::vector<std::string> extractCommandArguments(const std::string& command);
};
}

View File

@@ -1,14 +1,14 @@
Supported Bloom commands:
help Displays this help text.
version Outputs Bloom's version information.
version machine Outputs Bloom's version information in JSON format.
help Displays this help text.
version Outputs Bloom's version information.
version machine Outputs Bloom's version information in JSON format.
@ACTIVATE_INSIGHT_HELP_TEXT@
reset Resets the target and holds it in a stopped state.
reset Resets the target and holds it in a stopped state.
eeprom fill Fills the target's EEPROM with a specified value. The value should be specified via the
--value option. The value should be in hexadecimal format: "--value=AABBCC". If the specified
value is smaller than the EEPROM capacity, it will be repeated across the entire EEPROM address
range. If the value size is not a multiple of the EEPROM capacity, the value will be truncated
in the final repetition. The value size must not exceed the EEPROM capacity.
eeprom fill [VALUE] Fills the target's EEPROM with the specified value. The value should be in hexadecimal
format: "monitor eeprom fill AABBCC". If the specified value is smaller than the EEPROM
memory segment size, it will be repeated across the entire segment address range. If the
value size is not a multiple of the segment size, the value will be truncated in the final
repetition. The value size must not exceed the segment size.