Renamed AvrGdbRsp directory to AvrGdb and moved target register functions to new GDB target descriptor class
This commit is contained in:
17
src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.cpp
Normal file
17
src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
51
src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.hpp
Normal file
51
src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
149
src/DebugServers/GdbRsp/AvrGdb/TargetDescriptor.cpp
Normal file
149
src/DebugServers/GdbRsp/AvrGdb/TargetDescriptor.cpp
Normal 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
51
src/DebugServers/GdbRsp/AvrGdb/TargetDescriptor.hpp
Normal file
51
src/DebugServers/GdbRsp/AvrGdb/TargetDescriptor.hpp
Normal 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();
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user