This commit is contained in:
Nav
2024-11-28 21:49:03 +00:00
parent 9c1b194af1
commit 8e86cfb152
12 changed files with 67 additions and 54 deletions

View File

@@ -42,7 +42,7 @@ namespace DebugServer::Gdb::AvrGdb
{} {}
std::string AvrGdbRsp::getName() const { std::string AvrGdbRsp::getName() const {
return "AVR GDB Remote Serial Protocol Debug Server"; return "AVR GDB Remote Serial Protocol Server";
} }
std::unique_ptr<CommandPackets::AvrGdbCommandPacketInterface> AvrGdbRsp::rawPacketToCommandPacket( std::unique_ptr<CommandPackets::AvrGdbCommandPacketInterface> AvrGdbRsp::rawPacketToCommandPacket(

View File

@@ -11,6 +11,7 @@
#include "Exceptions/ClientCommunicationError.hpp" #include "Exceptions/ClientCommunicationError.hpp"
#include "src/Exceptions/Exception.hpp" #include "src/Exceptions/Exception.hpp"
#include "src/Exceptions/InternalFatalErrorException.hpp"
#include "src/Logger/Logger.hpp" #include "src/Logger/Logger.hpp"
#include "src/Services/StringService.hpp" #include "src/Services/StringService.hpp"
@@ -207,6 +208,10 @@ namespace DebugServer::Gdb
bool interruptible, bool interruptible,
std::optional<std::chrono::milliseconds> timeout std::optional<std::chrono::milliseconds> timeout
) { ) {
if (bytes.has_value() && *bytes > Connection::ABSOLUTE_MAXIMUM_PACKET_READ_SIZE) {
throw InternalFatalErrorException{"Attempted to read too many bytes from GDB socket"};
}
auto output = std::vector<unsigned char>{}; auto output = std::vector<unsigned char>{};
if (this->readInterruptEnabled != interruptible) { if (this->readInterruptEnabled != interruptible) {

View File

@@ -36,7 +36,7 @@ namespace DebugServer::Gdb
* The current server configuration. * The current server configuration.
* *
* TODO: I think this should be moved out of the DebugSession struct and passed into CommandPacket::handle() * TODO: I think this should be moved out of the DebugSession struct and passed into CommandPacket::handle()
* function. Review after v1.1.0. * function. Review after v2.0.0.
*/ */
const GdbDebugServerConfig& serverConfig; const GdbDebugServerConfig& serverConfig;

View File

@@ -117,10 +117,6 @@ namespace DebugServer::Gdb
GdbRspDebugServer& operator = (const GdbRspDebugServer& other) = delete; GdbRspDebugServer& operator = (const GdbRspDebugServer& other) = delete;
GdbRspDebugServer& operator = (GdbRspDebugServer&& other) = delete; GdbRspDebugServer& operator = (GdbRspDebugServer&& other) = delete;
[[nodiscard]] std::string getName() const override {
return "GDB Remote Serial Protocol DebugServer";
}
/** /**
* Prepares the GDB server for listing on the selected address and port. * Prepares the GDB server for listing on the selected address and port.
*/ */
@@ -291,6 +287,7 @@ namespace DebugServer::Gdb
return; return;
} catch (const ::Exceptions::FatalErrorException& exception) { } catch (const ::Exceptions::FatalErrorException& exception) {
Logger::error("Fatal error occurred - closing connection");
this->endDebugSession(); this->endDebugSession();
throw exception; throw exception;
} }

View File

@@ -28,8 +28,7 @@
#include "src/Exceptions/Exception.hpp" #include "src/Exceptions/Exception.hpp"
#include "src/Exceptions/InvalidConfig.hpp" #include "src/Exceptions/InvalidConfig.hpp"
#include "src/Exceptions/InternalFatalErrorException.hpp" #include "src/Exceptions/InternalFatalErrorException.hpp"
#include "src/TargetController/Exceptions/DeviceFailure.hpp" #include "src/TargetController/Exceptions/TargetFailure.hpp"
#include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp"
#include "src/TargetController/Exceptions/TargetOperationFailure.hpp" #include "src/TargetController/Exceptions/TargetOperationFailure.hpp"
#include "src/Logger/Logger.hpp" #include "src/Logger/Logger.hpp"
@@ -80,18 +79,13 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
void DebugTranslator::activate() { void DebugTranslator::activate() {
this->debugModuleDescriptor.hartIndices = this->discoverHartIndices(); this->debugModuleDescriptor.hartIndices = this->discoverHartIndices();
if (this->debugModuleDescriptor.hartIndices.empty()) { if (this->debugModuleDescriptor.hartIndices.empty()) {
throw Exceptions::TargetOperationFailure{"Failed to discover any RISC-V harts"}; throw Exceptions::TargetFailure{"Failed to discover any RISC-V harts"};
} }
Logger::debug("Discovered RISC-V harts: " + std::to_string(this->debugModuleDescriptor.hartIndices.size()));
/*
* We only support debugging a single RISC-V hart, for now.
*
* If we discover more than one, we select the first one and ensure that this is explicitly communicated to the
* user.
*/
if (this->debugModuleDescriptor.hartIndices.size() > 1) { if (this->debugModuleDescriptor.hartIndices.size() > 1) {
Logger::debug(
"Discovered RISC-V harts: " + std::to_string(this->debugModuleDescriptor.hartIndices.size())
);
Logger::warning("Bloom only supports debugging a single RISC-V hart - selecting first available"); Logger::warning("Bloom only supports debugging a single RISC-V hart - selecting first available");
} }
@@ -156,7 +150,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
} }
if (this->debugModuleDescriptor.memoryAccessStrategies.empty()) { if (this->debugModuleDescriptor.memoryAccessStrategies.empty()) {
throw Exceptions::TargetOperationFailure{"Target doesn't support any known memory access strategies"}; throw Exceptions::TargetFailure{"Target doesn't support any known memory access strategies"};
} }
this->memoryAccessStrategy = this->determineMemoryAccessStrategy(); this->memoryAccessStrategy = this->determineMemoryAccessStrategy();
@@ -203,7 +197,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
this->writeDebugModuleControlRegister(controlRegister); this->writeDebugModuleControlRegister(controlRegister);
if (!statusRegister.allHalted) { if (!statusRegister.allHalted) {
throw Exceptions::Exception{"Target took too long to halt selected harts"}; throw Exceptions::TargetOperationFailure{"Target took too long to halt selected harts"};
} }
} }
@@ -233,7 +227,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
if (!statusRegister.allResumeAcknowledge) { if (!statusRegister.allResumeAcknowledge) {
Logger::debug("Failed to resume target execution - stopping target"); Logger::debug("Failed to resume target execution - stopping target");
this->stop(); this->stop();
throw Exceptions::Exception{"Target took too long to acknowledge resume request"}; throw Exceptions::TargetOperationFailure{"Target took too long to acknowledge resume request"};
} }
} }
@@ -292,7 +286,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
}); });
if (!statusRegister.allHaveReset) { if (!statusRegister.allHaveReset) {
throw Exceptions::Exception{"Target took too long to reset"}; throw Exceptions::TargetOperationFailure{"Target took too long to reset"};
} }
this->initDebugControlStatusRegister(); this->initDebugControlStatusRegister();
@@ -307,7 +301,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
const auto triggerDescriptorOpt = this->getAvailableTrigger(); const auto triggerDescriptorOpt = this->getAvailableTrigger();
if (!triggerDescriptorOpt.has_value()) { if (!triggerDescriptorOpt.has_value()) {
throw Exceptions::Exception{"Insufficient resources - no available trigger"}; throw Exceptions::TargetOperationFailure{"Insufficient resources - no available trigger"};
} }
const auto& triggerDescriptor = triggerDescriptorOpt->get(); const auto& triggerDescriptor = triggerDescriptorOpt->get();
@@ -343,13 +337,13 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
return; return;
} }
throw Exceptions::Exception{"Unsupported trigger"}; throw Exceptions::TargetOperationFailure{"Unsupported trigger"};
} }
void DebugTranslator::clearTriggerBreakpoint(TargetMemoryAddress address) { void DebugTranslator::clearTriggerBreakpoint(TargetMemoryAddress address) {
const auto triggerIndexIt = this->triggerIndicesByBreakpointAddress.find(address); const auto triggerIndexIt = this->triggerIndicesByBreakpointAddress.find(address);
if (triggerIndexIt == this->triggerIndicesByBreakpointAddress.end()) { if (triggerIndexIt == this->triggerIndicesByBreakpointAddress.end()) {
throw Exceptions::Exception{"Unknown hardware breakpoint"}; throw Exceptions::TargetOperationFailure{"Unknown hardware breakpoint"};
} }
const auto& triggerDescriptor = this->debugModuleDescriptor.triggerDescriptorsByIndex.at(triggerIndexIt->second); const auto& triggerDescriptor = this->debugModuleDescriptor.triggerDescriptorsByIndex.at(triggerIndexIt->second);
@@ -566,7 +560,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
} }
if (writeSelectError != AbstractCommandError::NONE) { if (writeSelectError != AbstractCommandError::NONE) {
throw Exceptions::Exception{ throw Exceptions::TargetOperationFailure{
"Failed to write to TRIGGER_SELECT register - abstract command error: 0x" "Failed to write to TRIGGER_SELECT register - abstract command error: 0x"
+ Services::StringService::toHex(static_cast<std::uint8_t>(writeSelectError)) + Services::StringService::toHex(static_cast<std::uint8_t>(writeSelectError))
}; };
@@ -649,7 +643,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
} }
if (!controlRegister.debugModuleActive) { if (!controlRegister.debugModuleActive) {
throw Exceptions::Exception{"Took too long to enable debug module"}; throw Exceptions::TargetOperationFailure{"Took too long to enable debug module"};
} }
} }
@@ -671,7 +665,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
} }
if (controlRegister.debugModuleActive) { if (controlRegister.debugModuleActive) {
throw Exceptions::Exception{"Took too long to disable debug module"}; throw Exceptions::TargetOperationFailure{"Took too long to disable debug module"};
} }
} }
@@ -720,7 +714,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
const auto result = this->tryReadCpuRegister(number, flags); const auto result = this->tryReadCpuRegister(number, flags);
if (!result.hasValue()) { if (!result.hasValue()) {
throw Exceptions::Exception{ throw Exceptions::TargetOperationFailure{
"Failed to read CPU register (number: 0x" + Services::StringService::toHex(number) "Failed to read CPU register (number: 0x" + Services::StringService::toHex(number)
+ ") - abstract command error: 0x" + ") - abstract command error: 0x"
+ Services::StringService::toHex(static_cast<std::uint8_t>(result.error())) + Services::StringService::toHex(static_cast<std::uint8_t>(result.error()))
@@ -770,7 +764,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
) { ) {
const auto commandError = this->tryWriteCpuRegister(number, value, flags); const auto commandError = this->tryWriteCpuRegister(number, value, flags);
if (commandError != AbstractCommandError::NONE) { if (commandError != AbstractCommandError::NONE) {
throw Exceptions::Exception{ throw Exceptions::TargetOperationFailure{
"Failed to write to CPU register (number: 0x" + Services::StringService::toHex(number) "Failed to write to CPU register (number: 0x" + Services::StringService::toHex(number)
+ ") - abstract command error: 0x" + ") - abstract command error: 0x"
+ Services::StringService::toHex(static_cast<std::uint8_t>(commandError)) + Services::StringService::toHex(static_cast<std::uint8_t>(commandError))
@@ -825,7 +819,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
} }
if (abstractStatusRegister.busy) { if (abstractStatusRegister.busy) {
throw Exceptions::Exception{"Abstract command took too long to execute"}; throw Exceptions::TargetOperationFailure{"Abstract command took too long to execute"};
} }
if (abstractStatusRegister.commandError != AbstractCommandError::NONE) { if (abstractStatusRegister.commandError != AbstractCommandError::NONE) {
@@ -840,7 +834,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
) { ) {
const auto commandError = this->tryExecuteAbstractCommand(abstractCommandRegister); const auto commandError = this->tryExecuteAbstractCommand(abstractCommandRegister);
if (commandError != AbstractCommandError::NONE) { if (commandError != AbstractCommandError::NONE) {
throw Exceptions::Exception{ throw Exceptions::TargetOperationFailure{
"Failed to execute abstract command - error: 0x" "Failed to execute abstract command - error: 0x"
+ Services::StringService::toHex(static_cast<std::uint8_t>(commandError)) + Services::StringService::toHex(static_cast<std::uint8_t>(commandError))
}; };
@@ -969,7 +963,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
}); });
if (programOpcodes.size() > this->debugModuleDescriptor.programBufferSize) { if (programOpcodes.size() > this->debugModuleDescriptor.programBufferSize) {
throw Exceptions::Exception{ throw Exceptions::TargetOperationFailure{
"Cannot read memory via RISC-V debug module program buffer - insufficient program buffer size" "Cannot read memory via RISC-V debug module program buffer - insufficient program buffer size"
}; };
} }
@@ -1043,7 +1037,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
if (abstractStatusRegister.commandError != AbstractCommandError::NONE) { if (abstractStatusRegister.commandError != AbstractCommandError::NONE) {
this->clearAbstractCommandError(); this->clearAbstractCommandError();
throw Exceptions::Exception{ throw Exceptions::TargetOperationFailure{
"Program buffer execution failed - abstract command error: 0x" "Program buffer execution failed - abstract command error: 0x"
+ Services::StringService::toHex(abstractStatusRegister.commandError) + Services::StringService::toHex(abstractStatusRegister.commandError)
}; };
@@ -1091,7 +1085,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
}); });
if (programOpcodes.size() > this->debugModuleDescriptor.programBufferSize) { if (programOpcodes.size() > this->debugModuleDescriptor.programBufferSize) {
throw Exceptions::Exception{ throw Exceptions::TargetOperationFailure{
"Cannot write to memory via RISC-V debug module program buffer - insufficient program buffer size" "Cannot write to memory via RISC-V debug module program buffer - insufficient program buffer size"
}; };
} }
@@ -1144,7 +1138,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
if (abstractStatusRegister.commandError != AbstractCommandError::NONE) { if (abstractStatusRegister.commandError != AbstractCommandError::NONE) {
this->clearAbstractCommandError(); this->clearAbstractCommandError();
throw Exceptions::Exception{ throw Exceptions::TargetOperationFailure{
"Program buffer execution failed - abstract command error: 0x" "Program buffer execution failed - abstract command error: 0x"
+ Services::StringService::toHex(abstractStatusRegister.commandError) + Services::StringService::toHex(abstractStatusRegister.commandError)
}; };
@@ -1203,7 +1197,7 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
return; return;
} }
throw Exceptions::Exception{"Unsupported trigger"}; throw Exceptions::TargetOperationFailure{"Unsupported trigger"};
} }
DebugTranslator::PreservedCpuRegister::PreservedCpuRegister( DebugTranslator::PreservedCpuRegister::PreservedCpuRegister(
@@ -1238,9 +1232,9 @@ namespace DebugToolDrivers::Protocols::RiscVDebugSpec
* will be left in an undefined state. More specifically, the state of the program running on the target * will be left in an undefined state. More specifically, the state of the program running on the target
* may be corrupted. We cannot recover from this. * may be corrupted. We cannot recover from this.
* *
* DeviceFailure exceptions are considered to be fatal. A clean shutdown will follow. * TargetFailure exceptions are considered to be fatal. A clean shutdown will follow.
*/ */
throw Exceptions::DeviceFailure{ throw Exceptions::TargetFailure{
"Failed to restore CPU register (number: 0x" "Failed to restore CPU register (number: 0x"
+ Services::StringService::toHex(this->registerNumber) + ") - error: " + exception.getMessage() + Services::StringService::toHex(this->registerNumber) + ") - error: " + exception.getMessage()
+ " - the target is now in an undefined state and may require a reset" + " - the target is now in an undefined state and may require a reset"

View File

@@ -142,21 +142,24 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink
Targets::TargetMemoryAddress startAddress, Targets::TargetMemoryAddress startAddress,
Targets::TargetMemoryBufferSpan buffer Targets::TargetMemoryBufferSpan buffer
) { ) {
constexpr auto packetSize = std::uint8_t{64}; constexpr auto packetSize = WchLinkInterface::MAX_PARTIAL_BLOCK_WRITE_SIZE;
const auto bufferSize = static_cast<Targets::TargetMemorySize>(buffer.size()); const auto bufferSize = static_cast<Targets::TargetMemorySize>(buffer.size());
const auto packetsRequired = static_cast<std::uint32_t>( const auto packetsRequired = static_cast<std::size_t>(
std::ceil(static_cast<float>(bufferSize) / static_cast<float>(packetSize)) std::ceil(static_cast<float>(bufferSize) / static_cast<float>(packetSize))
); );
for (auto i = std::uint32_t{0}; i < packetsRequired; ++i) { for (auto i = std::size_t{0}; i < packetsRequired; ++i) {
const auto segmentSize = static_cast<std::uint8_t>( const auto segmentSize = std::min(
std::min( static_cast<Targets::TargetMemorySize>(bufferSize - (i * packetSize)),
static_cast<std::uint8_t>(bufferSize - (i * packetSize)),
packetSize packetSize
)
); );
assert(segmentSize <= 0xFF);
const auto response = this->sendCommandAndWaitForResponse( const auto response = this->sendCommandAndWaitForResponse(
Commands::PreparePartialFlashBlockWrite{startAddress + (packetSize * i), segmentSize} Commands::PreparePartialFlashBlockWrite{
static_cast<Targets::TargetMemorySize>(startAddress + (packetSize * i)),
static_cast<std::uint8_t>(segmentSize)
}
); );
if (response.payload.size() != 1) { if (response.payload.size() != 1) {

View File

@@ -30,6 +30,8 @@ namespace DebugToolDrivers::Wch::Protocols::WchLink
: public ::DebugToolDrivers::Protocols::RiscVDebugSpec::DebugTransportModuleInterface : public ::DebugToolDrivers::Protocols::RiscVDebugSpec::DebugTransportModuleInterface
{ {
public: public:
static constexpr Targets::TargetMemorySize MAX_PARTIAL_BLOCK_WRITE_SIZE = 64;
WchLinkInterface(Usb::UsbInterface& usbInterface, Usb::UsbDevice& usbDevice); WchLinkInterface(Usb::UsbInterface& usbInterface, Usb::UsbDevice& usbDevice);
DeviceInfo getDeviceInfo(); DeviceInfo getDeviceInfo();

View File

@@ -210,7 +210,7 @@ namespace DebugToolDrivers::Wch
* See WchLinkDebugInterface::writeFlashMemory() below, for more. * See WchLinkDebugInterface::writeFlashMemory() below, for more.
*/ */
const auto bufferSize = static_cast<TargetMemorySize>(buffer.size()); const auto bufferSize = static_cast<TargetMemorySize>(buffer.size());
const auto alignmentSize = bufferSize > WchLinkDebugInterface::MAX_PARTIAL_BLOCK_WRITE_SIZE const auto alignmentSize = bufferSize > WchLinkInterface::MAX_PARTIAL_BLOCK_WRITE_SIZE
? this->programmingBlockSize ? this->programmingBlockSize
: 1; : 1;
@@ -286,7 +286,7 @@ namespace DebugToolDrivers::Wch
* Writes any number of bytes to flash, but limited to a maximum of 64 bytes per write. Larger writes * Writes any number of bytes to flash, but limited to a maximum of 64 bytes per write. Larger writes
* must be split into multiple writes. * must be split into multiple writes.
* - Full block write * - Full block write
* Writes an entire block to flash. Where the block size is target-specific (resides in the target's * Writes an entire block to flash, where the block size is target-specific (resides in the target's
* TDF). Requires alignment to the block size. Requires reattaching to the target at the end of the * TDF). Requires alignment to the block size. Requires reattaching to the target at the end of the
* programming session. * programming session.
* *
@@ -294,7 +294,7 @@ namespace DebugToolDrivers::Wch
* target. But the partial block write is faster and more suitable for writing buffers that are smaller than * target. But the partial block write is faster and more suitable for writing buffers that are smaller than
* 64 bytes, such as when we're inserting software breakpoints. * 64 bytes, such as when we're inserting software breakpoints.
*/ */
if (buffer.size() <= WchLinkDebugInterface::MAX_PARTIAL_BLOCK_WRITE_SIZE) { if (buffer.size() <= WchLinkInterface::MAX_PARTIAL_BLOCK_WRITE_SIZE) {
return this->wchLinkInterface.writeFlashPartialBlock(startAddress, buffer); return this->wchLinkInterface.writeFlashPartialBlock(startAddress, buffer);
} }

View File

@@ -77,8 +77,6 @@ namespace DebugToolDrivers::Wch
) override; ) override;
private: private:
static constexpr Targets::TargetMemorySize MAX_PARTIAL_BLOCK_WRITE_SIZE = 64;
const WchLinkToolConfig& toolConfig; const WchLinkToolConfig& toolConfig;
const Targets::RiscV::RiscVTargetConfig& targetConfig; const Targets::RiscV::RiscVTargetConfig& targetConfig;
const Targets::RiscV::TargetDescriptionFile& targetDescriptionFile; const Targets::RiscV::TargetDescriptionFile& targetDescriptionFile;

View File

@@ -0,0 +1,14 @@
#pragma once
#include "src/Exceptions/FatalErrorException.hpp"
namespace Exceptions
{
class TargetFailure: public FatalErrorException
{
public:
explicit TargetFailure(const std::string& message)
: FatalErrorException(message)
{}
};
}

View File

@@ -118,7 +118,7 @@ namespace Targets::RiscV::Wch
* *
* @TODO: Currently, this just assumes that the alias segment always maps to the program memory segment, but I * @TODO: Currently, this just assumes that the alias segment always maps to the program memory segment, but I
* believe it may map to the boot program memory segment in some cases. This needs to be revisited * believe it may map to the boot program memory segment in some cases. This needs to be revisited
* before v1.1.0. * before v2.0.0.
*/ */
if (memorySegmentDescriptor == this->mappedProgramMemorySegmentDescriptor) { if (memorySegmentDescriptor == this->mappedProgramMemorySegmentDescriptor) {
const auto newAddress = startAddress - this->mappedProgramMemorySegmentDescriptor.addressRange.startAddress const auto newAddress = startAddress - this->mappedProgramMemorySegmentDescriptor.addressRange.startAddress

View File

@@ -10,7 +10,7 @@ namespace Targets
{ {
public: public:
std::string position; std::string position;
std::uint16_t numericPosition; // TODO: Consider removing this bodge. Review after v1.1.0 std::uint16_t numericPosition; // TODO: Consider removing this bodge. Review after v2.0.0
std::optional<std::string> padKey; std::optional<std::string> padKey;
TargetPinDescriptor( TargetPinDescriptor(