Added support for GDB's 'qXfer:memory-map:read::...' command packet.
This commit is contained in:
@@ -30,4 +30,5 @@ target_sources(
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/TargetDescriptor.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/TargetDescriptor.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/CommandPackets/ReadMemory.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/WriteMemory.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.cpp
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// Command packets
|
// Command packets
|
||||||
#include "CommandPackets/ReadMemory.hpp"
|
#include "CommandPackets/ReadMemory.hpp"
|
||||||
#include "CommandPackets/WriteMemory.hpp"
|
#include "CommandPackets/WriteMemory.hpp"
|
||||||
|
#include "CommandPackets/ReadMemoryMap.hpp"
|
||||||
|
|
||||||
namespace Bloom::DebugServer::Gdb::AvrGdb
|
namespace Bloom::DebugServer::Gdb::AvrGdb
|
||||||
{
|
{
|
||||||
@@ -32,6 +33,7 @@ namespace Bloom::DebugServer::Gdb::AvrGdb
|
|||||||
) {
|
) {
|
||||||
using AvrGdb::CommandPackets::ReadMemory;
|
using AvrGdb::CommandPackets::ReadMemory;
|
||||||
using AvrGdb::CommandPackets::WriteMemory;
|
using AvrGdb::CommandPackets::WriteMemory;
|
||||||
|
using AvrGdb::CommandPackets::ReadMemoryMap;
|
||||||
|
|
||||||
if (rawPacket.size() >= 2) {
|
if (rawPacket.size() >= 2) {
|
||||||
if (rawPacket[1] == 'm') {
|
if (rawPacket[1] == 'm') {
|
||||||
@@ -41,8 +43,25 @@ namespace Bloom::DebugServer::Gdb::AvrGdb
|
|||||||
if (rawPacket[1] == 'M') {
|
if (rawPacket[1] == 'M') {
|
||||||
return std::make_unique<WriteMemory>(rawPacket);
|
return std::make_unique<WriteMemory>(rawPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto rawPacketString = std::string(rawPacket.begin() + 1, rawPacket.end());
|
||||||
|
|
||||||
|
if (rawPacketString.find("qXfer:memory-map:read::") == 0) {
|
||||||
|
return std::make_unique<ReadMemoryMap>(rawPacket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return GdbRspDebugServer::resolveCommandPacket(rawPacket);
|
return GdbRspDebugServer::resolveCommandPacket(rawPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::set<std::pair<Feature, std::optional<std::string>>> AvrGdbRsp::getSupportedFeatures() {
|
||||||
|
auto supportedFeatures = GdbRspDebugServer::getSupportedFeatures();
|
||||||
|
|
||||||
|
// The AVR GDB server supports the
|
||||||
|
supportedFeatures.insert({
|
||||||
|
Feature::MEMORY_MAP_READ, std::nullopt
|
||||||
|
});
|
||||||
|
|
||||||
|
return supportedFeatures;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ namespace Bloom::DebugServer::Gdb::AvrGdb
|
|||||||
const RawPacketType& rawPacket
|
const RawPacketType& rawPacket
|
||||||
) override;
|
) override;
|
||||||
|
|
||||||
|
std::set<std::pair<Feature, std::optional<std::string>>> getSupportedFeatures() override ;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<TargetDescriptor> gdbTargetDescriptor;
|
std::optional<TargetDescriptor> gdbTargetDescriptor;
|
||||||
};
|
};
|
||||||
|
|||||||
93
src/DebugServer/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.cpp
Normal file
93
src/DebugServer/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.cpp
Normal file
@@ -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<const char*>(this->data.data() + 23), // +23 to exclude the "qXfer:memory-map:read::"
|
||||||
|
static_cast<int>(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("<memory-map>")
|
||||||
|
+ "<memory type=\"ram\" start=\"0x800000\" length=\"" + std::to_string(ramSize) + "\"/>"
|
||||||
|
+ "<memory type=\"flash\" start=\"0\" length=\"" + std::to_string(flashSize) + "\">"
|
||||||
|
+ "<property name=\"blocksize\">" + std::to_string(flashPageSize) + "</property>"
|
||||||
|
+ "</memory>"
|
||||||
|
+ "</memory-map>";
|
||||||
|
|
||||||
|
if (this->offset < memoryMap.size() && this->length > 0) {
|
||||||
|
auto memoryMapData = std::vector<unsigned char>(
|
||||||
|
memoryMap.begin() + this->offset,
|
||||||
|
memoryMap.begin() + std::min(
|
||||||
|
static_cast<long>(this->offset + this->length),
|
||||||
|
static_cast<long>(memoryMap.size())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto responseData = std::vector<unsigned char>({'l'});
|
||||||
|
std::move(memoryMapData.begin(), memoryMapData.end(), std::back_inserter(responseData));
|
||||||
|
|
||||||
|
debugSession.connection.writePacket(ResponsePacket(responseData));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugSession.connection.writePacket(ResponsePacket(std::vector<unsigned char>({'l'})));
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/DebugServer/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.hpp
Normal file
33
src/DebugServer/Gdb/AvrGdb/CommandPackets/ReadMemoryMap.hpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user