Lots of tidying

- Removed generic `avr8` target
- Simplified AVR8 target construction
- Introduced register descriptor IDs
- Simplified GDB register mappings
- Simplified target interface contract
- Other bits of tidying
This commit is contained in:
Nav
2023-05-21 21:08:25 +01:00
parent 5f8242a87a
commit ba03833325
62 changed files with 1304 additions and 1577 deletions

View File

@@ -1,6 +1,9 @@
#include "AvrGdbRsp.hpp"
// Command packets
#include "CommandPackets/ReadRegister.hpp"
#include "CommandPackets/ReadRegisters.hpp"
#include "CommandPackets/WriteRegister.hpp"
#include "CommandPackets/ReadMemory.hpp"
#include "CommandPackets/WriteMemory.hpp"
#include "CommandPackets/ReadMemoryMap.hpp"
@@ -34,6 +37,9 @@ namespace Bloom::DebugServer::Gdb::AvrGdb
std::unique_ptr<Gdb::CommandPackets::CommandPacket> AvrGdbRsp::resolveCommandPacket(
const RawPacket& rawPacket
) {
using AvrGdb::CommandPackets::ReadRegister;
using AvrGdb::CommandPackets::ReadRegisters;
using AvrGdb::CommandPackets::WriteRegister;
using AvrGdb::CommandPackets::ReadMemory;
using AvrGdb::CommandPackets::WriteMemory;
using AvrGdb::CommandPackets::ReadMemoryMap;
@@ -42,6 +48,18 @@ namespace Bloom::DebugServer::Gdb::AvrGdb
using AvrGdb::CommandPackets::FlashDone;
if (rawPacket.size() >= 2) {
if (rawPacket[1] == 'p') {
return std::make_unique<ReadRegister>(rawPacket);
}
if (rawPacket[1] == 'g') {
return std::make_unique<ReadRegisters>(rawPacket);
}
if (rawPacket[1] == 'P') {
return std::make_unique<WriteRegister>(rawPacket);
}
if (rawPacket[1] == 'm') {
return std::make_unique<ReadMemory>(rawPacket, this->gdbTargetDescriptor.value());
}

View File

@@ -0,0 +1,96 @@
#include "ReadRegister.hpp"
#include "src/DebugServer/Gdb/ResponsePackets/ErrorResponsePacket.hpp"
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
#include "src/Targets/TargetRegister.hpp"
#include "src/Services/StringService.hpp"
#include "src/Logger/Logger.hpp"
#include "src/Exceptions/Exception.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
{
using Services::TargetControllerService;
using Targets::TargetRegister;
using Targets::TargetRegisterDescriptors;
using ResponsePackets::ResponsePacket;
using ResponsePackets::ErrorResponsePacket;
using Exceptions::Exception;
ReadRegister::ReadRegister(const RawPacket& rawPacket)
: CommandPacket(rawPacket)
{
if (this->data.size() < 2) {
throw Exception("Invalid packet length");
}
this->registerId = static_cast<GdbRegisterId>(
std::stoi(std::string(this->data.begin() + 1, this->data.end()))
);
}
void ReadRegister::handle(DebugSession& debugSession, TargetControllerService& targetControllerService) {
Logger::info("Handling ReadRegister packet");
try {
Logger::debug("Reading GDB register ID: " + std::to_string(this->registerId));
if (this->registerId == TargetDescriptor::PROGRAM_COUNTER_GDB_REGISTER_ID) {
/*
* GDB has requested the program counter. We can't access this in the same way as we do with other
* registers.
*/
const auto programCounter = targetControllerService.getProgramCounter();
debugSession.connection.writePacket(
ResponsePacket(Services::StringService::toHex(Targets::TargetMemoryBuffer({
static_cast<unsigned char>(programCounter),
static_cast<unsigned char>(programCounter >> 8),
static_cast<unsigned char>(programCounter >> 16),
static_cast<unsigned char>(programCounter >> 24),
})))
);
return;
}
const auto& targetDescriptor = debugSession.gdbTargetDescriptor;
const auto& gdbRegisterDescriptor = targetDescriptor.gdbRegisterDescriptorsById.at(this->registerId);
const auto targetRegisterDescriptorId = targetDescriptor.getTargetRegisterDescriptorIdFromGdbRegisterId(
this->registerId
);
if (!targetRegisterDescriptorId.has_value()) {
throw Exception("GDB requested an invalid/unknown register");
}
auto registerValue = targetControllerService.readRegisters({*targetRegisterDescriptorId}).front().value;
// GDB expects register values to be in LSB.
std::reverse(registerValue.begin(), registerValue.end());
if (registerValue.size() < gdbRegisterDescriptor.size) {
/*
* The register on the target is smaller than the size expected by GDB.
*
* Insert the rest of the bytes.
*/
registerValue.insert(registerValue.end(), (gdbRegisterDescriptor.size - registerValue.size()), 0x00);
}
debugSession.connection.writePacket(
ResponsePacket(Services::StringService::toHex(registerValue))
);
} catch (const Exception& exception) {
Logger::error("Failed to read general registers - " + exception.getMessage());
debugSession.connection.writePacket(ErrorResponsePacket());
}
}
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
#include "src/DebugServer/Gdb/RegisterDescriptor.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
{
/**
* The ReadRegister class implements a structure for the "p" command packet. In response to this packet, the server
* is expected to send register values for the requested register.
*/
class ReadRegister: public Gdb::CommandPackets::CommandPacket
{
public:
GdbRegisterId registerId;
explicit ReadRegister(const RawPacket& rawPacket);
void handle(
DebugSession& debugSession,
Services::TargetControllerService& targetControllerService
) override;
};
}

View File

@@ -0,0 +1,99 @@
#include "ReadRegisters.hpp"
#include "src/DebugServer/Gdb/ResponsePackets/ErrorResponsePacket.hpp"
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
#include "src/Targets/TargetRegister.hpp"
#include "src/Services/StringService.hpp"
#include "src/Logger/Logger.hpp"
#include "src/Exceptions/Exception.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
{
using Services::TargetControllerService;
using Targets::TargetRegister;
using Targets::TargetRegisterDescriptorIds;
using ResponsePackets::ResponsePacket;
using ResponsePackets::ErrorResponsePacket;
using Exceptions::Exception;
ReadRegisters::ReadRegisters(const RawPacket& rawPacket)
: CommandPacket(rawPacket)
{}
void ReadRegisters::handle(DebugSession& debugSession, TargetControllerService& targetControllerService) {
Logger::info("Handling ReadRegisters packet");
try {
const auto& targetDescriptor = debugSession.gdbTargetDescriptor;
auto descriptorIds = TargetRegisterDescriptorIds();
// Read all target registers mapped to a GDB register
for (const auto& [gdbRegisterId, gdbRegisterDescriptor] : targetDescriptor.gdbRegisterDescriptorsById) {
const auto registerDescriptorId = targetDescriptor.getTargetRegisterDescriptorIdFromGdbRegisterId(
gdbRegisterId
);
if (registerDescriptorId.has_value()) {
descriptorIds.insert(*registerDescriptorId);
}
}
auto registerSet = targetControllerService.readRegisters(descriptorIds);
/*
* Sort each register by their respective GDB register ID - this will leave us with a collection of
* registers in the order expected by the GDB client.
*/
std::sort(
registerSet.begin(),
registerSet.end(),
[this, &targetDescriptor] (const TargetRegister& regA, const TargetRegister& regB) {
return targetDescriptor.getGdbRegisterIdFromTargetRegisterDescriptorId(regA.descriptorId).value() <
targetDescriptor.getGdbRegisterIdFromTargetRegisterDescriptorId(regB.descriptorId).value();
}
);
/*
* Reverse the register values (as they're all currently in MSB, but GDB expects them in LSB), ensure that
* each register value size matches the size in the associated GDB register descriptor and implode the
* values.
*/
auto registers = std::vector<unsigned char>();
for (auto& reg : registerSet) {
std::reverse(reg.value.begin(), reg.value.end());
const auto gdbRegisterId = targetDescriptor.getGdbRegisterIdFromTargetRegisterDescriptorId(
reg.descriptorId
).value();
const auto& gdbRegisterDescriptor = targetDescriptor.gdbRegisterDescriptorsById.at(gdbRegisterId);
if (reg.value.size() < gdbRegisterDescriptor.size) {
reg.value.insert(reg.value.end(), (gdbRegisterDescriptor.size - reg.value.size()), 0x00);
}
registers.insert(registers.end(), reg.value.begin(), reg.value.end());
}
// Finally, include the program counter (which GDB expects to reside at the end)
const auto programCounter = targetControllerService.getProgramCounter();
registers.insert(registers.end(), static_cast<unsigned char>(programCounter));
registers.insert(registers.end(), static_cast<unsigned char>(programCounter >> 8));
registers.insert(registers.end(), static_cast<unsigned char>(programCounter >> 16));
registers.insert(registers.end(), static_cast<unsigned char>(programCounter >> 24));
debugSession.connection.writePacket(
ResponsePacket(Services::StringService::toHex(registers))
);
} catch (const Exception& exception) {
Logger::error("Failed to read registers - " + exception.getMessage());
debugSession.connection.writePacket(ErrorResponsePacket());
}
}
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include <optional>
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
#include "src/DebugServer/Gdb/RegisterDescriptor.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
{
/**
* The ReadRegisters class implements a structure for the "g" command packet. In response to this packet, the
* server is expected to send register values for all registers.
*/
class ReadRegisters: public Gdb::CommandPackets::CommandPacket
{
public:
explicit ReadRegisters(const RawPacket& rawPacket);
void handle(
DebugSession& debugSession,
Services::TargetControllerService& targetControllerService
) override;
};
}

View File

@@ -0,0 +1,110 @@
#include "WriteRegister.hpp"
#include "src/DebugServer/Gdb/ResponsePackets/OkResponsePacket.hpp"
#include "src/DebugServer/Gdb/ResponsePackets/ErrorResponsePacket.hpp"
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
#include "src/Logger/Logger.hpp"
#include "src/Exceptions/Exception.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
{
using Services::TargetControllerService;
using Targets::TargetRegister;
using Targets::TargetRegisterDescriptors;
using ResponsePackets::ResponsePacket;
using ResponsePackets::OkResponsePacket;
using ResponsePackets::ErrorResponsePacket;
using Exceptions::Exception;
WriteRegister::WriteRegister(const RawPacket& rawPacket)
: CommandPacket(rawPacket)
{
// The P packet updates a single register
auto packet = std::string(this->data.begin(), this->data.end());
if (packet.size() < 4) {
throw Exception("Invalid WriteRegister command packet - insufficient data in packet.");
}
if (packet.find('=') == std::string::npos) {
throw Exception("Invalid WriteRegister command packet - unexpected format");
}
const auto packetSegments = QString::fromStdString(packet).split("=");
this->registerId = static_cast<GdbRegisterId>(packetSegments.front().mid(1).toUInt(nullptr, 16));
this->registerValue = Packet::hexToData(packetSegments.back().toStdString());
if (this->registerValue.empty()) {
throw Exception("Invalid WriteRegister command packet - missing register value");
}
std::reverse(this->registerValue.begin(), this->registerValue.end());
}
void WriteRegister::handle(DebugSession& debugSession, TargetControllerService& targetControllerService) {
Logger::info("Handling WriteRegister packet");
try {
if (this->registerId == TargetDescriptor::PROGRAM_COUNTER_GDB_REGISTER_ID) {
targetControllerService.setProgramCounter(
static_cast<Targets::TargetProgramCounter>(
(this->registerValue.size() >= 1 ? this->registerValue[0] : 0x00) << 24
| (this->registerValue.size() >= 2 ? this->registerValue[1] : 0x00) << 16
| (this->registerValue.size() >= 3 ? this->registerValue[2] : 0x00) << 8
| (this->registerValue.size() >= 4 ? this->registerValue[3] : 0x00)
)
);
debugSession.connection.writePacket(OkResponsePacket());
return;
}
const auto& gdbTargetDescriptor = debugSession.gdbTargetDescriptor;
const auto descriptorId = gdbTargetDescriptor.getTargetRegisterDescriptorIdFromGdbRegisterId(
this->registerId
);
if (!descriptorId.has_value()) {
throw Exception("Invalid/unknown register");
}
const auto& descriptor = gdbTargetDescriptor.targetDescriptor.registerDescriptorsById.at(*descriptorId);
if (this->registerValue.size() > descriptor.size) {
// Attempt to trim the higher zero-value bytes from the register value, until we reach the correct size.
for (auto i = this->registerValue.size() - 1; i >= descriptor.size; --i) {
if (this->registerValue.at(i) != 0x00) {
// If we reach a non-zero byte, we cannot trim anymore without changing the data
break;
}
this->registerValue.erase(this->registerValue.begin() + i);
}
if (this->registerValue.size() > descriptor.size) {
const auto& gdbRegisterDescriptor = gdbTargetDescriptor.gdbRegisterDescriptorsById.at(
this->registerId
);
throw Exception(
"Cannot set value for " + gdbRegisterDescriptor.name + " - value size exceeds register size."
);
}
}
targetControllerService.writeRegisters({
TargetRegister(descriptor.id, this->registerValue)
});
debugSession.connection.writePacket(OkResponsePacket());
} catch (const Exception& exception) {
Logger::error("Failed to write registers - " + exception.getMessage());
debugSession.connection.writePacket(ErrorResponsePacket());
}
}
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
#include "src/DebugServer/Gdb/RegisterDescriptor.hpp"
#include "src/Targets/TargetRegister.hpp"
#include "src/Targets/TargetMemory.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb::CommandPackets
{
/**
* The WriteRegister class implements the structure for "P" packets.
*/
class WriteRegister: public Gdb::CommandPackets::CommandPacket
{
public:
GdbRegisterId registerId;
Targets::TargetMemoryBuffer registerValue;
explicit WriteRegister(const RawPacket& rawPacket);
void handle(
DebugSession& debugSession,
Services::TargetControllerService& targetControllerService
) override;
};
}

View File

@@ -19,164 +19,143 @@ namespace Bloom::DebugServer::Gdb::AvrGdb
{Targets::TargetMemoryType::FLASH, 0},
{Targets::TargetMemoryType::RAM, 0x00800000U},
{Targets::TargetMemoryType::EEPROM, 0x00810000U},
}
},
{},
{},
{}
)
{
this->loadRegisterMappings();
}
std::optional<GdbRegisterNumber> TargetDescriptor::getRegisterNumberFromTargetRegisterDescriptor(
const Targets::TargetRegisterDescriptor& registerDescriptor
) const {
return this->targetRegisterDescriptorsByGdbNumber.valueAt(registerDescriptor);
}
const RegisterDescriptor& TargetDescriptor::getRegisterDescriptorFromNumber(GdbRegisterNumber number) const {
const auto registerDescriptorIt = this->registerDescriptorsByGdbNumber.find(number);
if (registerDescriptorIt.has_value()) {
return (*registerDescriptorIt)->second;
}
throw Exception(
"Unknown register from GDB - register number (" + std::to_string(number)
+ ") not mapped to any GDB register descriptor."
);
}
const TargetRegisterDescriptor& TargetDescriptor::getTargetRegisterDescriptorFromNumber(
GdbRegisterNumber number
) const {
const auto targetRegisterDescriptorIt = this->targetRegisterDescriptorsByGdbNumber.find(number);
if (targetRegisterDescriptorIt.has_value()) {
return (*targetRegisterDescriptorIt)->second;
}
throw Exception(
"Unknown register from GDB - register number (" + std::to_string(number)
+ ") not mapped to any target register descriptor."
);
}
const std::vector<GdbRegisterNumber>& TargetDescriptor::getRegisterNumbers() const {
return this->registerNumbers;
}
void TargetDescriptor::loadRegisterMappings() {
const auto& registerDescriptorsByType = this->targetDescriptor.registerDescriptorsByType;
if (!registerDescriptorsByType.contains(TargetRegisterType::STATUS_REGISTER)) {
throw Exception("Missing status register descriptor");
}
if (!registerDescriptorsByType.contains(TargetRegisterType::STACK_POINTER)) {
throw Exception("Missing stack pointer register descriptor");
}
if (!registerDescriptorsByType.contains(TargetRegisterType::PROGRAM_COUNTER)) {
throw Exception("Missing program counter register descriptor");
}
if (
!registerDescriptorsByType.contains(TargetRegisterType::GENERAL_PURPOSE_REGISTER)
|| registerDescriptorsByType.at(TargetRegisterType::GENERAL_PURPOSE_REGISTER).size() != 32
) {
throw Exception("Unexpected general purpose register count");
}
/*
* For AVR targets, avr-gdb defines 35 registers in total:
*
* Register number 0 through 31 are general purpose registers
* Register number 32 is the status register (SREG)
* Register number 33 is the stack pointer register
* Register number 34 is the program counter register
*/
// Generate 35 register numbers (0 -> 34)
std::iota(this->registerNumbers.begin(), this->registerNumbers.end(), 0);
/*
* Worth noting that gpRegisterDescriptors will always be sorted in the correct order, from register 0 to 31.
*
* Hmm, but the sorting is based on the start address (see TargetRegisterDescriptor::<() for more). So
* effectively, we're assuming that the registers will be laid out in the correct order, in memory. I think
* this assumption is fair.
*/
const auto& gpRegisterDescriptors = registerDescriptorsByType.at(
const auto generalPurposeTargetRegisterDescriptorIds = this->targetDescriptor.registerDescriptorIdsForType(
TargetRegisterType::GENERAL_PURPOSE_REGISTER
);
// General purpose registers
GdbRegisterNumber regNumber = 0;
for (const auto& descriptor : gpRegisterDescriptors) {
this->registerDescriptorsByGdbNumber.insert(std::pair(
regNumber,
RegisterDescriptor(
regNumber,
1,
"General Purpose Register " + std::to_string(regNumber)
)
));
const auto statusTargetRegisterDescriptorIds = this->targetDescriptor.registerDescriptorIdsForType(
TargetRegisterType::STATUS_REGISTER
);
this->targetRegisterDescriptorsByGdbNumber.insert(std::pair(
regNumber,
descriptor
));
const auto stackPointerTargetRegisterDescriptorIds = this->targetDescriptor.registerDescriptorIdsForType(
TargetRegisterType::STACK_POINTER
);
regNumber++;
if (generalPurposeTargetRegisterDescriptorIds.size() != 32) {
throw Exception("Unexpected general purpose register count");
}
// Status, stack pointer and program counter registers
const auto statusDescriptor = RegisterDescriptor(
32,
if (statusTargetRegisterDescriptorIds.empty()) {
throw Exception("Missing status register descriptor");
}
if (stackPointerTargetRegisterDescriptorIds.empty()) {
throw Exception("Missing stack pointer register descriptor");
}
/*
* For AVR targets, GDB defines 35 registers in total:
*
* - Register ID 0 through 31 are general purpose registers
* - Register ID 32 is the status register (SREG)
* - Register ID 33 is the stack pointer register
* - Register ID 34 is the program counter
*
* For AVR targets, we don't have a target register descriptor for the program counter, so we don't map that
* GDB register ID (34) to anything here. Instead, the register command packet handlers (ReadRegisters,
* WriteRegister, etc) will handle any operations involving that GDB register.
*/
// General purpose registers
GdbRegisterId gdbRegisterId = 0;
for (const auto descriptorId : generalPurposeTargetRegisterDescriptorIds) {
auto gdbRegisterDescriptor = RegisterDescriptor(
gdbRegisterId,
1,
"General Purpose Register " + std::to_string(gdbRegisterId)
);
this->gdbRegisterIdsByTargetRegisterDescriptorId.emplace(descriptorId, gdbRegisterDescriptor.id);
this->targetRegisterDescriptorIdsByGdbRegisterId.emplace(gdbRegisterDescriptor.id, descriptorId);
this->gdbRegisterDescriptorsById.emplace(gdbRegisterDescriptor.id, std::move(gdbRegisterDescriptor));
gdbRegisterId++;
}
const auto& statusTargetRegisterDescriptor = this->targetDescriptor.registerDescriptorsById.at(
*(statusTargetRegisterDescriptorIds.begin())
);
auto statusGdbRegisterDescriptor = RegisterDescriptor(
TargetDescriptor::STATUS_GDB_REGISTER_ID,
1,
"Status Register"
);
this->registerDescriptorsByGdbNumber.insert(std::pair(statusDescriptor.number, statusDescriptor));
this->targetRegisterDescriptorsByGdbNumber.insert(std::pair(
statusDescriptor.number,
*(registerDescriptorsByType.at(TargetRegisterType::STATUS_REGISTER).begin())
));
if (statusTargetRegisterDescriptor.size > statusGdbRegisterDescriptor.size) {
throw Exception("AVR8 status target register size exceeds the GDB register size.");
}
const auto stackPointerDescriptor = RegisterDescriptor(
33,
this->gdbRegisterIdsByTargetRegisterDescriptorId.emplace(
statusTargetRegisterDescriptor.id,
statusGdbRegisterDescriptor.id
);
this->targetRegisterDescriptorIdsByGdbRegisterId.emplace(
statusGdbRegisterDescriptor.id,
statusTargetRegisterDescriptor.id
);
this->gdbRegisterDescriptorsById.emplace(
statusGdbRegisterDescriptor.id,
std::move(statusGdbRegisterDescriptor)
);
const auto& stackPointerTargetRegisterDescriptor = this->targetDescriptor.registerDescriptorsById.at(
*(stackPointerTargetRegisterDescriptorIds.begin())
);
auto stackPointerGdbRegisterDescriptor = RegisterDescriptor(
TargetDescriptor::STACK_POINTER_GDB_REGISTER_ID,
2,
"Stack Pointer Register"
);
this->registerDescriptorsByGdbNumber.insert(std::pair(stackPointerDescriptor.number, stackPointerDescriptor));
this->targetRegisterDescriptorsByGdbNumber.insert(std::pair(
stackPointerDescriptor.number,
*(registerDescriptorsByType.at(TargetRegisterType::STACK_POINTER).begin())
));
if (stackPointerTargetRegisterDescriptor.size > stackPointerGdbRegisterDescriptor.size) {
throw Exception("AVR8 stack pointer target register size exceeds the GDB register size.");
}
const auto programCounterDescriptor = RegisterDescriptor(
34,
this->gdbRegisterIdsByTargetRegisterDescriptorId.emplace(
stackPointerTargetRegisterDescriptor.id,
stackPointerGdbRegisterDescriptor.id
);
this->targetRegisterDescriptorIdsByGdbRegisterId.emplace(
stackPointerGdbRegisterDescriptor.id,
stackPointerTargetRegisterDescriptor.id
);
this->gdbRegisterDescriptorsById.emplace(
stackPointerGdbRegisterDescriptor.id,
std::move(stackPointerGdbRegisterDescriptor)
);
/*
* We acknowledge the GDB program counter register here, but we don't map it to any target register descriptors.
*
* This is because we can't access the program counter on AVR targets in the same way we do with other
* registers. We don't have a register descriptor for the program counter. We have to treat it as a special
* case in the register access command packet handlers. See CommandPackets::ReadRegister,
* CommandPackets::WriteRegister, etc for more.
*/
auto programCounterGdbRegisterDescriptor = RegisterDescriptor(
TargetDescriptor::PROGRAM_COUNTER_GDB_REGISTER_ID,
4,
"Program Counter"
);
this->registerDescriptorsByGdbNumber.insert(std::pair(
programCounterDescriptor.number,
programCounterDescriptor
));
this->targetRegisterDescriptorsByGdbNumber.insert(std::pair(
programCounterDescriptor.number,
*(registerDescriptorsByType.at(TargetRegisterType::PROGRAM_COUNTER).begin())
));
if (registerDescriptorsByType.at(TargetRegisterType::STATUS_REGISTER).size() > statusDescriptor.size) {
throw Exception("AVR8 status target register size exceeds the GDB register size.");
}
if (registerDescriptorsByType.at(TargetRegisterType::STACK_POINTER).size() > stackPointerDescriptor.size) {
throw Exception("AVR8 stack pointer target register size exceeds the GDB register size.");
}
if (
registerDescriptorsByType.at(TargetRegisterType::PROGRAM_COUNTER).size() > programCounterDescriptor.size
) {
throw Exception("AVR8 program counter size exceeds the GDB register size.");
}
this->gdbRegisterDescriptorsById.emplace(
programCounterGdbRegisterDescriptor.id,
std::move(programCounterGdbRegisterDescriptor)
);
}
}

View File

@@ -2,52 +2,18 @@
#include "src/DebugServer/Gdb/TargetDescriptor.hpp"
#include "src/Helpers/BiMap.hpp"
namespace Bloom::DebugServer::Gdb::AvrGdb
{
class TargetDescriptor: public DebugServer::Gdb::TargetDescriptor
{
public:
BiMap<GdbRegisterNumber, RegisterDescriptor> registerDescriptorsByGdbNumber = {};
BiMap<GdbRegisterNumber, Targets::TargetRegisterDescriptor> targetRegisterDescriptorsByGdbNumber = {};
static constexpr auto STATUS_GDB_REGISTER_ID = 32;
static constexpr auto STACK_POINTER_GDB_REGISTER_ID = 33;
static constexpr auto PROGRAM_COUNTER_GDB_REGISTER_ID = 34;
explicit TargetDescriptor(const Targets::TargetDescriptor& targetDescriptor);
/**
* 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.
*
* @param registerDescriptor
* @return
*/
std::optional<GdbRegisterNumber> getRegisterNumberFromTargetRegisterDescriptor(
const Targets::TargetRegisterDescriptor& registerDescriptor
) const override;
/**
* Should retrieve the GDB register descriptor for a given GDB register number.
*
* @param number
* @return
*/
const RegisterDescriptor& getRegisterDescriptorFromNumber(GdbRegisterNumber number) const override;
/**
* Should retrieve the mapped target register descriptor for a given GDB register number.
*
* @param number
* @return
*/
const Targets::TargetRegisterDescriptor& getTargetRegisterDescriptorFromNumber(
GdbRegisterNumber number
) const override;
const std::vector<GdbRegisterNumber>& getRegisterNumbers() const override;
private:
std::vector<GdbRegisterNumber> registerNumbers = std::vector<GdbRegisterNumber>(35);
/**
* For AVR targets, avr-gdb defines 35 registers in total:
*