From f1e20c81a2dabeab950c82268678d4eefd6e8277 Mon Sep 17 00:00:00 2001 From: Nav Date: Sat, 14 May 2022 22:43:08 +0100 Subject: [PATCH] Added support for GDB's 'qXfer:memory-map:read::...' command packet. --- src/DebugServer/CMakeLists.txt | 1 + src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.cpp | 19 ++++ src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.hpp | 2 + .../AvrGdb/CommandPackets/ReadMemoryMap.cpp | 93 +++++++++++++++++++ .../AvrGdb/CommandPackets/ReadMemoryMap.hpp | 33 +++++++ 5 files changed, 148 insertions(+) create mode 100644 src/DebugServer/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.cpp create mode 100644 src/DebugServer/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.hpp diff --git a/src/DebugServer/CMakeLists.txt b/src/DebugServer/CMakeLists.txt index 664e4310..dcd9c423 100755 --- a/src/DebugServer/CMakeLists.txt +++ b/src/DebugServer/CMakeLists.txt @@ -30,4 +30,5 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/TargetDescriptor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/CommandPackets/ReadMemory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/CommandPackets/WriteMemory.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.cpp ) diff --git a/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.cpp b/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.cpp index 360d7168..865e27fc 100644 --- a/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.cpp +++ b/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.cpp @@ -3,6 +3,7 @@ // Command packets #include "CommandPackets/ReadMemory.hpp" #include "CommandPackets/WriteMemory.hpp" +#include "CommandPackets/ReadMemoryMap.hpp" namespace Bloom::DebugServer::Gdb::AvrGdb { @@ -32,6 +33,7 @@ namespace Bloom::DebugServer::Gdb::AvrGdb ) { using AvrGdb::CommandPackets::ReadMemory; using AvrGdb::CommandPackets::WriteMemory; + using AvrGdb::CommandPackets::ReadMemoryMap; if (rawPacket.size() >= 2) { if (rawPacket[1] == 'm') { @@ -41,8 +43,25 @@ namespace Bloom::DebugServer::Gdb::AvrGdb if (rawPacket[1] == 'M') { return std::make_unique(rawPacket); } + + const auto rawPacketString = std::string(rawPacket.begin() + 1, rawPacket.end()); + + if (rawPacketString.find("qXfer:memory-map:read::") == 0) { + return std::make_unique(rawPacket); + } } return GdbRspDebugServer::resolveCommandPacket(rawPacket); } + + std::set>> AvrGdbRsp::getSupportedFeatures() { + auto supportedFeatures = GdbRspDebugServer::getSupportedFeatures(); + + // The AVR GDB server supports the + supportedFeatures.insert({ + Feature::MEMORY_MAP_READ, std::nullopt + }); + + return supportedFeatures; + } } diff --git a/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.hpp b/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.hpp index 90b57120..c2dba1d7 100644 --- a/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.hpp +++ b/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.hpp @@ -47,6 +47,8 @@ namespace Bloom::DebugServer::Gdb::AvrGdb const RawPacketType& rawPacket ) override; + std::set>> getSupportedFeatures() override ; + private: std::optional gdbTargetDescriptor; }; diff --git a/src/DebugServer/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.cpp b/src/DebugServer/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.cpp new file mode 100644 index 00000000..89856e3e --- /dev/null +++ b/src/DebugServer/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.cpp @@ -0,0 +1,93 @@ +#include "ReadMemoryMap.hpp" + +#include "src/DebugServer/Gdb/ResponsePackets/ResponsePacket.hpp" + +#include "src/Exceptions/Exception.hpp" + +namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets +{ + using TargetController::TargetControllerConsole; + + using ResponsePackets::ResponsePacket; + + using Exceptions::Exception; + + ReadMemoryMap::ReadMemoryMap(const RawPacketType& rawPacket) + : CommandPacket(rawPacket) + { + if (this->data.size() < 26) { + throw Exception("Invalid packet length"); + } + + auto packetString = QString::fromLocal8Bit( + reinterpret_cast(this->data.data() + 23), // +23 to exclude the "qXfer:memory-map:read::" + static_cast(this->data.size() - 23) + ); + + /* + * The read memory map ('qXfer:memory-map:read::...') packet consists of two segments, an offset and a length. + * These are separated by a comma character. + */ + auto packetSegments = packetString.split(","); + + if (packetSegments.size() != 2) { + throw Exception( + "Unexpected number of segments in packet data: " + std::to_string(packetSegments.size()) + ); + } + + bool conversionStatus = false; + this->offset = packetSegments.at(0).toUInt(&conversionStatus, 10); + + if (!conversionStatus) { + throw Exception("Failed to parse offset from read memory map packet data"); + } + + this->length = packetSegments.at(1).toUInt(&conversionStatus, 10); + + if (!conversionStatus) { + throw Exception("Failed to parse read length from read memory map packet data"); + } + } + + void ReadMemoryMap::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) { + Logger::debug("Handling ReadMemoryMap packet"); + + using Targets::TargetMemoryType; + const auto& memoryDescriptorsByType = debugSession.gdbTargetDescriptor.targetDescriptor.memoryDescriptorsByType; + + const auto& ramDescriptor = memoryDescriptorsByType.at(TargetMemoryType::RAM); + const auto& flashDescriptor = memoryDescriptorsByType.at(TargetMemoryType::FLASH); + + // We include the start address in ramSize to account for AVR registers in the data address space. + const auto ramSize = ramDescriptor.size() + ramDescriptor.addressRange.startAddress; + const auto flashSize = flashDescriptor.size(); + const auto flashPageSize = flashDescriptor.pageSize.value(); + + const auto memoryMap = + std::string("") + + "" + + "" + + "" + std::to_string(flashPageSize) + "" + + "" + + ""; + + if (this->offset < memoryMap.size() && this->length > 0) { + auto memoryMapData = std::vector( + memoryMap.begin() + this->offset, + memoryMap.begin() + std::min( + static_cast(this->offset + this->length), + static_cast(memoryMap.size()) + ) + ); + + auto responseData = std::vector({'l'}); + std::move(memoryMapData.begin(), memoryMapData.end(), std::back_inserter(responseData)); + + debugSession.connection.writePacket(ResponsePacket(responseData)); + return; + } + + debugSession.connection.writePacket(ResponsePacket(std::vector({'l'}))); + } +} diff --git a/src/DebugServer/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.hpp b/src/DebugServer/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.hpp new file mode 100644 index 00000000..6532ffeb --- /dev/null +++ b/src/DebugServer/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp" + +namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets +{ + /** + * The ReadMemoryMap class implements a structure for "qXfer:memory-map:read::..." packet. Upon receiving this + * packet, the server is expected to respond with the target's memory map. + */ + class ReadMemoryMap: public Gdb::CommandPackets::CommandPacket + { + public: + /** + * The offset of the memory map, from which to read. + */ + std::uint32_t offset = 0; + + /** + * The length of the memory map to read. + */ + std::uint32_t length = 0; + + explicit ReadMemoryMap(const RawPacketType& rawPacket); + + void handle( + DebugSession& debugSession, + TargetController::TargetControllerConsole& targetControllerConsole + ) override; + }; +}