Removed MemoryAccessCommandPacket class and moved GDB memory offsets to GDB TargetDescriptor class

This commit is contained in:
Nav
2022-08-30 02:04:35 +01:00
parent fd68089214
commit 2ae3786130
16 changed files with 114 additions and 92 deletions

View File

@@ -43,11 +43,11 @@ namespace Bloom::DebugServer::Gdb::AvrGdb
if (rawPacket.size() >= 2) {
if (rawPacket[1] == 'm') {
return std::make_unique<ReadMemory>(rawPacket);
return std::make_unique<ReadMemory>(rawPacket, this->gdbTargetDescriptor.value());
}
if (rawPacket[1] == 'M') {
return std::make_unique<WriteMemory>(rawPacket);
return std::make_unique<WriteMemory>(rawPacket, this->gdbTargetDescriptor.value());
}
const auto rawPacketString = std::string(rawPacket.begin() + 1, rawPacket.end());

View File

@@ -16,7 +16,7 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
using namespace Bloom::Exceptions;
FlashDone::FlashDone(const RawPacketType& rawPacket)
: MemoryAccessCommandPacket(rawPacket)
: CommandPacket(rawPacket)
{}
void FlashDone::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {

View File

@@ -3,14 +3,17 @@
#include <cstdint>
#include <optional>
#include "MemoryAccessCommandPacket.hpp"
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
#include "src/DebugServer/Gdb/TargetDescriptor.hpp"
#include "src/Targets/TargetMemory.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
{
/**
* The FlashDone class implements the structure for the "vFlashDone" packet.
*/
class FlashDone: public MemoryAccessCommandPacket
class FlashDone: public Gdb::CommandPackets::CommandPacket
{
public:
explicit FlashDone(const RawPacketType& rawPacket);

View File

@@ -16,7 +16,7 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
using namespace Bloom::Exceptions;
FlashErase::FlashErase(const RawPacketType& rawPacket)
: MemoryAccessCommandPacket(rawPacket)
: CommandPacket(rawPacket)
{
const auto packetString = QString::fromLocal8Bit(
reinterpret_cast<const char*>(this->data.data() + 12),

View File

@@ -3,7 +3,10 @@
#include <cstdint>
#include <optional>
#include "MemoryAccessCommandPacket.hpp"
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
#include "src/DebugServer/Gdb/TargetDescriptor.hpp"
#include "src/Targets/TargetMemory.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
{
@@ -11,7 +14,7 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
* The FlashErase class implements the structure for the "vFlashErase" packet. Upon receiving this packet, the
* server is expected to erase a particular region of the target's flash memory.
*/
class FlashErase: public MemoryAccessCommandPacket
class FlashErase: public Gdb::CommandPackets::CommandPacket
{
public:
std::uint32_t startAddress = 0;

View File

@@ -18,7 +18,7 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
using namespace Bloom::Exceptions;
FlashWrite::FlashWrite(const RawPacketType& rawPacket)
: MemoryAccessCommandPacket(rawPacket)
: CommandPacket(rawPacket)
{
if (this->data.size() < 15) {
throw Exception("Invalid packet length");

View File

@@ -3,7 +3,10 @@
#include <cstdint>
#include <optional>
#include "MemoryAccessCommandPacket.hpp"
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
#include "src/DebugServer/Gdb/TargetDescriptor.hpp"
#include "src/Targets/TargetMemory.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
{
@@ -11,7 +14,7 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
* The FlashWrite class implements the structure for the "vFlashWrite" packet. Upon receiving this packet, the
* server is expected to write to a particular region of the target's flash memory.
*/
class FlashWrite: public MemoryAccessCommandPacket
class FlashWrite: public Gdb::CommandPackets::CommandPacket
{
public:
std::uint32_t startAddress = 0;

View File

@@ -1,62 +0,0 @@
#pragma once
#include <cstdint>
#include <optional>
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
#include "src/Targets/TargetMemory.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
{
/**
* The MemoryAccessCommandPacket class is a base class for memory access GDB commands that are specific to the AVR
* architecture.
*
* With the GDB implementation for the AVR architecture, read/write memory commands include a special memory
* address. The memory type (FLASH, RAM, EEPROM, etc) is embedded within the 7 most significant bits of the second
* most significant byte of the memory address.
*
* This class provides functions to extract and remove the memory type from a given memory address.
*/
class MemoryAccessCommandPacket: public Bloom::DebugServer::Gdb::CommandPackets::CommandPacket
{
public:
explicit MemoryAccessCommandPacket(const RawPacketType& rawPacket)
: CommandPacket(rawPacket)
{};
protected:
/**
* The mask used by the AVR GDB client to encode the memory type into memory addresses.
*/
static constexpr std::uint32_t AVR_GDB_MEMORY_ADDRESS_MASK = 0x00FE0000U;
/**
* avr-gdb uses the most significant 15 bits in memory addresses to indicate the type of memory being
* addressed.
*
* @param address
* @return
*/
Targets::TargetMemoryType getMemoryTypeFromGdbAddress(std::uint32_t address) {
if ((address & MemoryAccessCommandPacket::AVR_GDB_MEMORY_ADDRESS_MASK) != 0U) {
return Targets::TargetMemoryType::RAM;
}
return Targets::TargetMemoryType::FLASH;
}
/**
* Strips the most significant 15 bits from a GDB memory address.
*
* @param address
* @return
*/
std::uint32_t removeMemoryTypeIndicatorFromGdbAddress(std::uint32_t address) {
return (address & MemoryAccessCommandPacket::AVR_GDB_MEMORY_ADDRESS_MASK) != 0U
? (address & ~(MemoryAccessCommandPacket::AVR_GDB_MEMORY_ADDRESS_MASK))
: address;
}
};
}

View File

@@ -15,8 +15,8 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
using Exceptions::Exception;
ReadMemory::ReadMemory(const RawPacketType& rawPacket)
: MemoryAccessCommandPacket(rawPacket)
ReadMemory::ReadMemory(const RawPacketType& rawPacket, const TargetDescriptor& gdbTargetDescriptor)
: CommandPacket(rawPacket)
{
if (this->data.size() < 4) {
throw Exception("Invalid packet length");
@@ -46,8 +46,8 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
throw Exception("Failed to parse start address from read memory packet data");
}
this->memoryType = this->getMemoryTypeFromGdbAddress(gdbStartAddress);
this->startAddress = this->removeMemoryTypeIndicatorFromGdbAddress(gdbStartAddress);
this->memoryType = gdbTargetDescriptor.getMemoryTypeFromGdbAddress(gdbStartAddress);
this->startAddress = gdbStartAddress & ~(gdbTargetDescriptor.getMemoryOffset(this->memoryType));
this->bytes = packetSegments.at(1).toUInt(&conversionStatus, 16);

View File

@@ -3,7 +3,10 @@
#include <cstdint>
#include <optional>
#include "MemoryAccessCommandPacket.hpp"
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
#include "src/DebugServer/Gdb/TargetDescriptor.hpp"
#include "src/Targets/TargetMemory.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
{
@@ -11,7 +14,7 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
* The ReadMemory class implements a structure for "m" packets. Upon receiving these packets, the server is
* expected to read memory from the target and send it the client.
*/
class ReadMemory: public MemoryAccessCommandPacket
class ReadMemory: public Gdb::CommandPackets::CommandPacket
{
public:
/**
@@ -29,7 +32,7 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
*/
std::uint32_t bytes = 0;
explicit ReadMemory(const RawPacketType& rawPacket);
explicit ReadMemory(const RawPacketType& rawPacket, const Gdb::TargetDescriptor& gdbTargetDescriptor);
void handle(
DebugSession& debugSession,

View File

@@ -59,6 +59,14 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
const auto& ramDescriptor = memoryDescriptorsByType.at(TargetMemoryType::RAM);
const auto& flashDescriptor = memoryDescriptorsByType.at(TargetMemoryType::FLASH);
const auto ramGdbOffset = debugSession.gdbTargetDescriptor.getMemoryOffset(
Targets::TargetMemoryType::RAM
);
const auto flashGdbOffset = debugSession.gdbTargetDescriptor.getMemoryOffset(
Targets::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();
@@ -66,8 +74,8 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
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) + "\">"
+ "<memory type=\"ram\" start=\"" + std::to_string(ramGdbOffset) + "\" length=\"" + std::to_string(ramSize) + "\"/>"
+ "<memory type=\"flash\" start=\"" + std::to_string(flashGdbOffset) + "\" length=\"" + std::to_string(flashSize) + "\">"
+ "<property name=\"blocksize\">" + std::to_string(flashPageSize) + "</property>"
+ "</memory>"
+ "</memory-map>";

View File

@@ -15,8 +15,8 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
using namespace Bloom::Exceptions;
WriteMemory::WriteMemory(const RawPacketType& rawPacket)
: MemoryAccessCommandPacket(rawPacket)
WriteMemory::WriteMemory(const RawPacketType& rawPacket, const TargetDescriptor& gdbTargetDescriptor)
: CommandPacket(rawPacket)
{
if (this->data.size() < 4) {
throw Exception("Invalid packet length");
@@ -45,8 +45,8 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
throw Exception("Failed to parse start address from write memory packet data");
}
this->memoryType = this->getMemoryTypeFromGdbAddress(gdbStartAddress);
this->startAddress = this->removeMemoryTypeIndicatorFromGdbAddress(gdbStartAddress);
this->memoryType = gdbTargetDescriptor.getMemoryTypeFromGdbAddress(gdbStartAddress);
this->startAddress = gdbStartAddress & ~(gdbTargetDescriptor.getMemoryOffset(this->memoryType));
auto lengthAndBufferSegments = packetSegments.at(1).split(":");
if (lengthAndBufferSegments.size() != 2) {

View File

@@ -3,7 +3,10 @@
#include <cstdint>
#include <optional>
#include "MemoryAccessCommandPacket.hpp"
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
#include "src/DebugServer/Gdb/TargetDescriptor.hpp"
#include "src/Targets/TargetMemory.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
{
@@ -11,7 +14,7 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
* The WriteMemory class implements the structure for "M" packets. Upon receiving this packet, the server is
* expected to write data to the target's memory, at the specified start address.
*/
class WriteMemory: public MemoryAccessCommandPacket
class WriteMemory: public Gdb::CommandPackets::CommandPacket
{
public:
/**
@@ -29,7 +32,7 @@ namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
*/
Targets::TargetMemoryBuffer buffer;
explicit WriteMemory(const RawPacketType& rawPacket);
explicit WriteMemory(const RawPacketType& rawPacket, const Gdb::TargetDescriptor& gdbTargetDescriptor);
void handle(
DebugSession& debugSession,

View File

@@ -13,7 +13,13 @@ namespace Bloom::DebugServer::Gdb::AvrGdb
using Bloom::Exceptions::Exception;
TargetDescriptor::TargetDescriptor(const Bloom::Targets::TargetDescriptor& targetDescriptor)
: DebugServer::Gdb::TargetDescriptor(targetDescriptor)
: DebugServer::Gdb::TargetDescriptor(
targetDescriptor,
{
{Targets::TargetMemoryType::FLASH, 0},
{Targets::TargetMemoryType::RAM, 0x00800000U},
}
)
{
this->loadRegisterMappings();
}

View File

@@ -3,9 +3,12 @@
#include <cstdint>
#include <optional>
#include <vector>
#include <set>
#include "src/Helpers/BiMap.hpp"
#include "src/Targets/TargetDescriptor.hpp"
#include "src/Targets/TargetRegister.hpp"
#include "src/Targets/TargetMemory.hpp"
#include "RegisterDescriptor.hpp"
@@ -14,14 +17,41 @@ namespace Bloom::DebugServer::Gdb
/**
* GDB target descriptor.
*/
struct TargetDescriptor
class TargetDescriptor
{
public:
Targets::TargetDescriptor targetDescriptor;
explicit TargetDescriptor(const Targets::TargetDescriptor& targetDescriptor)
explicit TargetDescriptor(
const Targets::TargetDescriptor& targetDescriptor,
const BiMap<Targets::TargetMemoryType, std::uint32_t>& memoryOffsetsByType
)
: targetDescriptor(targetDescriptor)
, memoryOffsetsByType(memoryOffsetsByType)
, memoryOffsets(memoryOffsetsByType.getValues())
{}
virtual ~TargetDescriptor() = default;
virtual std::uint32_t getMemoryOffset(Targets::TargetMemoryType memoryType) const {
return this->memoryOffsetsByType.valueAt(memoryType).value_or(0);
}
Targets::TargetMemoryType getMemoryTypeFromGdbAddress(std::uint32_t address) const {
// Start with the largest offset until we find a match
for (
auto memoryOffsetIt = this->memoryOffsets.rbegin();
memoryOffsetIt != this->memoryOffsets.rend();
++memoryOffsetIt
) {
if ((address & *memoryOffsetIt) != 0U) {
return this->memoryOffsetsByType.at(*memoryOffsetIt);
}
}
return Targets::TargetMemoryType::FLASH;
}
/**
* Should retrieve the GDB register number, given a target register descriptor. Or std::nullopt if the target
* register descriptor isn't mapped to any GDB register.
@@ -57,5 +87,9 @@ namespace Bloom::DebugServer::Gdb
* @return
*/
virtual const std::vector<GdbRegisterNumberType>& getRegisterNumbers() const = 0;
private:
BiMap<Targets::TargetMemoryType, std::uint32_t> memoryOffsetsByType;
std::set<std::uint32_t> memoryOffsets;
};
}

View File

@@ -2,6 +2,7 @@
#include <memory>
#include <unordered_map>
#include <set>
namespace Bloom
{
@@ -67,6 +68,26 @@ namespace Bloom
return this->map;
}
[[nodiscard]] std::set<TypeB> getKeys() const {
auto keys = std::set<TypeB>();
for (const auto& [key, value] : this->map) {
keys.insert(key);
}
return keys;
}
[[nodiscard]] std::set<TypeB> getValues() const {
auto values = std::set<TypeB>();
for (const auto& [key, value] : this->map) {
values.insert(value);
}
return values;
}
void insert(const std::pair<TypeA, TypeB>& pair) {
auto insertResultPair = this->map.insert(pair);
this->flippedMap.insert(std::pair<TypeB, TypeA>(pair.second, pair.first));