Removed MemoryAccessCommandPacket class and moved GDB memory offsets to GDB TargetDescriptor class
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>";
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user