Renamed AvrGdbRsp directory to AvrGdb and moved target register functions to new GDB target descriptor class

This commit is contained in:
Nav
2022-03-24 19:06:09 +00:00
parent 5d58bbde07
commit 01396afcec
7 changed files with 156 additions and 146 deletions

View File

@@ -0,0 +1,17 @@
#include "AvrGdbRsp.hpp"
#include "src/Exceptions/Exception.hpp"
namespace Bloom::DebugServers::Gdb::AvrGdb
{
using namespace Bloom::Exceptions;
using Bloom::Targets::TargetRegisterDescriptor;
using Bloom::Targets::TargetRegisterType;
void AvrGdbRsp::init() {
DebugServers::Gdb::GdbRspDebugServer::init();
this->gdbTargetDescriptor = TargetDescriptor(this->targetDescriptor);
}
}

View File

@@ -0,0 +1,51 @@
#pragma once
#include <cstdint>
#include "TargetDescriptor.hpp"
#include "src/DebugServers/GdbRsp/GdbRspDebugServer.hpp"
#include "src/DebugServers/GdbRsp/RegisterDescriptor.hpp"
#include "src/Helpers/BiMap.hpp"
namespace Bloom::DebugServers::Gdb::AvrGdb
{
/**
* The AVR GDB client (avr-gdb) defines a set of parameters relating to AVR targets. These parameters are
* hardcoded in the AVR GDB source code. The client expects all compatible GDB RSP servers to be aware of
* these parameters.
*
* An example of these hardcoded parameters is target registers and the order in which they are supplied; AVR GDB
* clients expect 35 registers to be accessible via the server. 32 of these registers are general purpose CPU
* registers. The GP registers are expected to be followed by the status register (SREG), stack pointer
* register (SPH & SPL) and the program counter. These must all be given in a specific order, which is
* pre-determined by the AVR GDB client. See AvrGdbRsp::getRegisterNumberToDescriptorMapping() for more.
*
* For more on this, see the AVR GDB source code at https://github.com/bminor/binutils-gdb/blob/master/gdb/avr-tdep.c
*
* The AvrGdpRsp class extends the generic GDB RSP debug server and implements these AVR specific parameters.
*/
class AvrGdbRsp: public GdbRspDebugServer
{
public:
explicit AvrGdbRsp(
const ProjectConfig& projectConfig,
const EnvironmentConfig& environmentConfig,
const DebugServerConfig& debugServerConfig
): GdbRspDebugServer(projectConfig, environmentConfig, debugServerConfig) {};
std::string getName() const override {
return "AVR GDB Remote Serial Protocol Debug Server";
}
protected:
void init() override;
const Gdb::TargetDescriptor& getGdbTargetDescriptor() override {
return this->gdbTargetDescriptor;
}
private:
TargetDescriptor gdbTargetDescriptor;
};
}

View File

@@ -0,0 +1,149 @@
#include "TargetDescriptor.hpp"
#include "src/Exceptions/Exception.hpp"
#include "src/Logger/Logger.hpp"
namespace Bloom::DebugServers::Gdb::AvrGdb
{
using Bloom::Targets::TargetRegisterDescriptor;
using Bloom::Targets::TargetRegisterType;
using Bloom::Exceptions::Exception;
TargetDescriptor::TargetDescriptor(const Bloom::Targets::TargetDescriptor& targetDescriptor)
: DebugServers::Gdb::TargetDescriptor(targetDescriptor)
{
this->loadRegisterMappings();
}
std::optional<GdbRegisterNumberType> TargetDescriptor::getRegisterNumberFromTargetRegisterDescriptor(
const Targets::TargetRegisterDescriptor& registerDescriptor
) {
return this->targetRegisterDescriptorsByGdbNumber.valueAt(registerDescriptor);
}
const RegisterDescriptor& TargetDescriptor::getRegisterDescriptorFromNumber(GdbRegisterNumberType number) {
if (this->registerDescriptorsByGdbNumber.contains(number)) {
return this->registerDescriptorsByGdbNumber.at(number);
}
throw Exception("Unknown register from GDB - register number (" + std::to_string(number)
+ ") not mapped to any GDB register descriptor.");
}
const TargetRegisterDescriptor& TargetDescriptor::getTargetRegisterDescriptorFromNumber(GdbRegisterNumberType number) {
if (this->targetRegisterDescriptorsByGdbNumber.contains(number)) {
return this->targetRegisterDescriptorsByGdbNumber.at(number);
}
throw Exception("Unknown register from GDB - register number (" + std::to_string(number)
+ ") not mapped to any target register descriptor.");
}
void TargetDescriptor::loadRegisterMappings() {
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");
}
/*
* 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(
TargetRegisterType::GENERAL_PURPOSE_REGISTER
);
// General purpose CPU registers
GdbRegisterNumberType regNumber = 0;
for (const auto& descriptor : gpRegisterDescriptors) {
this->registerDescriptorsByGdbNumber.insert(std::pair(
regNumber,
RegisterDescriptor(
regNumber,
1,
"General Purpose Register " + std::to_string(regNumber)
)
));
this->targetRegisterDescriptorsByGdbNumber.insert(std::pair(
regNumber,
descriptor
));
regNumber++;
}
const auto statusDescriptor = RegisterDescriptor(
32,
1,
"Status Register"
);
this->registerDescriptorsByGdbNumber.insert(std::pair(statusDescriptor.number, statusDescriptor));
this->targetRegisterDescriptorsByGdbNumber.insert(std::pair(
statusDescriptor.number,
*(registerDescriptorsByType.at(TargetRegisterType::STATUS_REGISTER).begin())
));
const auto stackPointerDescriptor = RegisterDescriptor(
33,
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())
));
const auto programCounterDescriptor = RegisterDescriptor(
34,
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.");
}
}
}

View File

@@ -0,0 +1,51 @@
#pragma once
#include "src/DebugServers/GdbRsp/TargetDescriptor.hpp"
#include "src/Helpers/BiMap.hpp"
namespace Bloom::DebugServers::Gdb::AvrGdb
{
class TargetDescriptor: public DebugServers::Gdb::TargetDescriptor
{
public:
BiMap<GdbRegisterNumberType, RegisterDescriptor> registerDescriptorsByGdbNumber = {};
BiMap<GdbRegisterNumberType, Targets::TargetRegisterDescriptor> targetRegisterDescriptorsByGdbNumber = {};
const Bloom::Targets::TargetDescriptor& targetDescriptor;
explicit TargetDescriptor(const Bloom::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<GdbRegisterNumberType> getRegisterNumberFromTargetRegisterDescriptor(
const Targets::TargetRegisterDescriptor& registerDescriptor
) override;
/**
* Should retrieve the GDB register descriptor for a given GDB register number.
*
* @param number
* @return
*/
const RegisterDescriptor& getRegisterDescriptorFromNumber(GdbRegisterNumberType number) override;
/**
* Should retrieve the mapped target register descriptor for a given GDB register number.
*
* @param number
* @return
*/
const Targets::TargetRegisterDescriptor& getTargetRegisterDescriptorFromNumber(
GdbRegisterNumberType number
) override;
private:
void loadRegisterMappings();
};
}