New monitor eeprom fill GDB command
This commit is contained in:
@@ -25,6 +25,7 @@ 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/CommandPackets/EepromFill.cpp
|
||||
|
||||
# AVR GDB RSP Server
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/AvrGdbRsp.cpp
|
||||
|
||||
110
src/DebugServer/Gdb/CommandPackets/EepromFill.cpp
Normal file
110
src/DebugServer/Gdb/CommandPackets/EepromFill.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#include "EepromFill.hpp"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <algorithm>
|
||||
|
||||
#include "src/DebugServer/Gdb/ResponsePackets/ResponsePacket.hpp"
|
||||
#include "src/DebugServer/Gdb/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
|
||||
#include "src/DebugServer/Gdb/Exceptions/InvalidCommandOption.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
#include "src/Logger/Logger.hpp"
|
||||
|
||||
namespace Bloom::DebugServer::Gdb::CommandPackets
|
||||
{
|
||||
using TargetController::TargetControllerConsole;
|
||||
|
||||
using ResponsePackets::ResponsePacket;
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
using Bloom::Exceptions::Exception;
|
||||
using Exceptions::InvalidCommandOption;
|
||||
|
||||
EepromFill::EepromFill(Monitor&& monitorPacket)
|
||||
: Monitor(std::move(monitorPacket))
|
||||
{
|
||||
const auto fillValueOptionIt = this->commandOptions.find("value");
|
||||
|
||||
if (fillValueOptionIt == this->commandOptions.end() || !fillValueOptionIt->second.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto fillValueByteArray = QByteArray::fromHex(QByteArray::fromStdString(*fillValueOptionIt->second));
|
||||
this->fillValue = Targets::TargetMemoryBuffer(fillValueByteArray.begin(), fillValueByteArray.end());
|
||||
}
|
||||
|
||||
void EepromFill::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {
|
||||
Logger::debug("Handling EepromFill packet");
|
||||
|
||||
try {
|
||||
const auto& targetDescriptor = debugSession.gdbTargetDescriptor.targetDescriptor;
|
||||
|
||||
const auto eepromDescriptorIt = targetDescriptor.memoryDescriptorsByType.find(
|
||||
Targets::TargetMemoryType::EEPROM
|
||||
);
|
||||
|
||||
if (eepromDescriptorIt == targetDescriptor.memoryDescriptorsByType.end()) {
|
||||
throw Exception("Target has no EEPROM");
|
||||
}
|
||||
|
||||
const auto& eepromDescriptor = eepromDescriptorIt->second;
|
||||
const auto eepromSize = eepromDescriptor.size();
|
||||
|
||||
const auto fillValueSize = this->fillValue.size();
|
||||
|
||||
if (fillValueSize == 0) {
|
||||
throw InvalidCommandOption("Fill value required");
|
||||
}
|
||||
|
||||
if (fillValueSize > eepromSize) {
|
||||
throw InvalidCommandOption(
|
||||
"Fill value size ("+ std::to_string(fillValueSize) + " bytes) exceeds EEPROM size ("
|
||||
+ std::to_string(eepromSize) + " bytes)"
|
||||
);
|
||||
}
|
||||
|
||||
if ((eepromSize % fillValueSize) != 0) {
|
||||
Logger::warning(
|
||||
"The fill value size (" + std::to_string(fillValueSize) + " bytes) is not a multiple of the EEPROM "
|
||||
"size (" + std::to_string(eepromSize) + " bytes) - the fill value will be truncated"
|
||||
);
|
||||
}
|
||||
|
||||
Logger::warning("Filling " + std::to_string(eepromSize) + " bytes of EEPROM");
|
||||
|
||||
auto data = Targets::TargetMemoryBuffer();
|
||||
data.reserve(eepromSize);
|
||||
|
||||
// Repeat this->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>(
|
||||
std::min(fillValueSize, (eepromSize - data.size()))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const auto hexValues = Packet::toHex(data);
|
||||
Logger::debug("Filling EEPROM with values: " + hexValues);
|
||||
|
||||
targetControllerConsole.writeMemory(
|
||||
Targets::TargetMemoryType::EEPROM,
|
||||
eepromDescriptor.addressRange.startAddress,
|
||||
std::move(data)
|
||||
);
|
||||
|
||||
debugSession.connection.writePacket(ResponsePacket(Packet::toHex(
|
||||
"Filled " + std::to_string(eepromSize) + " bytes of EEPROM, with values: " + hexValues + "\n"
|
||||
)));
|
||||
|
||||
} catch (const InvalidCommandOption& exception) {
|
||||
Logger::error(exception.getMessage());
|
||||
debugSession.connection.writePacket(ResponsePacket(Packet::toHex(exception.getMessage() + "\n")));
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to fill EEPROM - " + exception.getMessage());
|
||||
debugSession.connection.writePacket(ErrorResponsePacket());
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/DebugServer/Gdb/CommandPackets/EepromFill.hpp
Normal file
29
src/DebugServer/Gdb/CommandPackets/EepromFill.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "Monitor.hpp"
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
|
||||
namespace Bloom::DebugServer::Gdb::CommandPackets
|
||||
{
|
||||
/**
|
||||
* The EepromFill class implements a structure for the "monitor eeprom fill" GDB command.
|
||||
*
|
||||
* This command fills the target's EEPROM with the given value.
|
||||
*/
|
||||
class EepromFill: public Monitor
|
||||
{
|
||||
public:
|
||||
explicit EepromFill(Monitor&& monitorPacket);
|
||||
|
||||
void handle(
|
||||
DebugSession& debugSession,
|
||||
TargetController::TargetControllerConsole& targetControllerConsole
|
||||
) override;
|
||||
|
||||
private:
|
||||
Targets::TargetMemoryBuffer fillValue;
|
||||
};
|
||||
}
|
||||
26
src/DebugServer/Gdb/Exceptions/InvalidCommandOption.hpp
Normal file
26
src/DebugServer/Gdb/Exceptions/InvalidCommandOption.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom::DebugServer::Gdb::Exceptions
|
||||
{
|
||||
/**
|
||||
* For GDB monitor commands, each command can define a set of required/optional command options.
|
||||
* This exception is thrown if an invalid option is given.
|
||||
*
|
||||
* This exception is typically thrown and caught within the handling of monitor commands.
|
||||
*/
|
||||
class InvalidCommandOption: public Bloom::Exceptions::Exception
|
||||
{
|
||||
public:
|
||||
explicit InvalidCommandOption(const std::string& message)
|
||||
: Bloom::Exceptions::Exception(message)
|
||||
{}
|
||||
|
||||
explicit InvalidCommandOption(const char* message)
|
||||
: Bloom::Exceptions::Exception(message)
|
||||
{}
|
||||
|
||||
explicit InvalidCommandOption() = default;
|
||||
};
|
||||
}
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "CommandPackets/BloomVersionMachine.hpp"
|
||||
#include "CommandPackets/GenerateSvd.hpp"
|
||||
#include "CommandPackets/Detach.hpp"
|
||||
#include "CommandPackets/EepromFill.hpp"
|
||||
|
||||
// Response packets
|
||||
#include "ResponsePackets/TargetStopped.hpp"
|
||||
@@ -314,6 +315,10 @@ namespace Bloom::DebugServer::Gdb
|
||||
return std::make_unique<CommandPackets::GenerateSvd>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
|
||||
if (monitorCommand->command.find("eeprom fill") == 0) {
|
||||
return std::make_unique<CommandPackets::EepromFill>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
|
||||
return monitorCommand;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user