Created new ServerInterface class and refactored the AVR GDB RSP debug server into an implementation of ServerInterface

This commit is contained in:
Nav
2022-03-27 18:32:13 +01:00
parent 5d3211dc68
commit 934c4b2820
9 changed files with 159 additions and 132 deletions

View File

@@ -390,15 +390,9 @@ namespace Bloom
} }
void Application::startDebugServer() { void Application::startDebugServer() {
auto supportedDebugServers = this->getSupportedDebugServers(); this->debugServer = std::make_unique<DebugServers::DebugServer>(
if (!supportedDebugServers.contains(this->debugServerConfig->name)) { this->debugServerConfig.value()
throw Exceptions::InvalidConfig( );
"DebugServer \"" + this->debugServerConfig->name + "\" not found."
);
}
this->debugServer = supportedDebugServers.at(this->debugServerConfig->name)();
Logger::info("Selected DebugServer: " + this->debugServer->getName());
this->debugServerThread = std::thread( this->debugServerThread = std::thread(
&DebugServers::DebugServer::run, &DebugServers::DebugServer::run,
@@ -414,7 +408,6 @@ namespace Bloom
void Application::stopDebugServer() { void Application::stopDebugServer() {
if (this->debugServer == nullptr) { if (this->debugServer == nullptr) {
// DebugServer hasn't been resolved yet.
return; return;
} }

View File

@@ -10,7 +10,7 @@
#include "src/Helpers/Thread.hpp" #include "src/Helpers/Thread.hpp"
#include "src/TargetController/TargetController.hpp" #include "src/TargetController/TargetController.hpp"
#include "src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.hpp" #include "src/DebugServers/DebugServer.hpp"
#include "src/Insight/Insight.hpp" #include "src/Insight/Insight.hpp"
#include "src/SignalHandler/SignalHandler.hpp" #include "src/SignalHandler/SignalHandler.hpp"
@@ -37,29 +37,6 @@ namespace Bloom
explicit Application() = default; explicit Application() = default;
/**
* This mapping is used to map debug server names from project configuration files to polymorphic instances of
* the DebugServer class.
*
* See Application::startDebugServer() for more on this.
*
* @return
*/
auto getSupportedDebugServers() {
return std::map<std::string, std::function<std::unique_ptr<DebugServers::DebugServer>()>> {
{
"avr-gdb-rsp",
[this] () -> std::unique_ptr<DebugServers::DebugServer> {
return std::make_unique<DebugServers::Gdb::AvrGdb::AvrGdbRsp>(
this->projectConfig.value(),
this->environmentConfig.value(),
this->debugServerConfig.value()
);
}
},
};
};
/** /**
* Main entry-point for the Bloom program. * Main entry-point for the Bloom program.
* *

View File

@@ -2,6 +2,9 @@
#include <variant> #include <variant>
// Debug server implementations
#include "GdbRsp/AvrGdb/AvrGdbRsp.hpp"
#include "src/Exceptions/InvalidConfig.hpp" #include "src/Exceptions/InvalidConfig.hpp"
#include "src/Logger/Logger.hpp" #include "src/Logger/Logger.hpp"
@@ -9,6 +12,10 @@ namespace Bloom::DebugServers
{ {
using namespace Bloom::Events; using namespace Bloom::Events;
DebugServer::DebugServer(const DebugServerConfig& debugServerConfig)
: debugServerConfig(debugServerConfig)
{}
void DebugServer::run() { void DebugServer::run() {
try { try {
this->startup(); this->startup();
@@ -16,7 +23,7 @@ namespace Bloom::DebugServers
Logger::info("DebugServer ready"); Logger::info("DebugServer ready");
while (this->getThreadState() == ThreadState::READY) { while (this->getThreadState() == ThreadState::READY) {
this->serve(); this->server->run();
this->eventListener->dispatchCurrentEvents(); this->eventListener->dispatchCurrentEvents();
} }
} catch (const std::exception& exception) { } catch (const std::exception& exception) {
@@ -26,23 +33,42 @@ namespace Bloom::DebugServers
this->shutdown(); this->shutdown();
} }
std::map<std::string, std::function<std::unique_ptr<ServerInterface>()>> DebugServer::getAvailableServersByName() {
return std::map<std::string, std::function<std::unique_ptr<ServerInterface>()>> {
{
"avr-gdb-rsp",
[this] () -> std::unique_ptr<ServerInterface> {
return std::make_unique<DebugServers::Gdb::AvrGdb::AvrGdbRsp>(
this->debugServerConfig,
*(this->eventListener.get())
);
}
},
};
}
void DebugServer::startup() { void DebugServer::startup() {
this->setName("DS"); this->setName("DS");
Logger::info("Starting DebugServer"); Logger::info("Starting DebugServer");
EventManager::registerListener(this->eventListener); EventManager::registerListener(this->eventListener);
this->eventListener->setInterruptEventNotifier(&this->interruptEventNotifier);
this->interruptEventNotifier = std::make_shared<EventNotifier>();
this->eventListener->setInterruptEventNotifier(this->interruptEventNotifier);
// Register event handlers // Register event handlers
this->eventListener->registerCallbackForEventType<Events::ShutdownDebugServer>( this->eventListener->registerCallbackForEventType<Events::ShutdownDebugServer>(
std::bind(&DebugServer::onShutdownDebugServerEvent, this, std::placeholders::_1) std::bind(&DebugServer::onShutdownDebugServerEvent, this, std::placeholders::_1)
); );
this->targetDescriptor = this->targetControllerConsole.getTargetDescriptor(); static const auto availableServersByName = this->getAvailableServersByName();
if (!availableServersByName.contains(this->debugServerConfig.name)) {
throw Exceptions::InvalidConfig(
"DebugServer \"" + this->debugServerConfig.name + "\" not found."
);
}
this->init(); this->server = availableServersByName.at(this->debugServerConfig.name)();
Logger::info("Selected DebugServer: " + this->server->getName());
this->server->init();
this->setThreadStateAndEmitEvent(ThreadState::READY); this->setThreadStateAndEmitEvent(ThreadState::READY);
} }
@@ -55,7 +81,7 @@ namespace Bloom::DebugServers
this->setThreadState(ThreadState::SHUTDOWN_INITIATED); this->setThreadState(ThreadState::SHUTDOWN_INITIATED);
Logger::info("Shutting down DebugServer"); Logger::info("Shutting down DebugServer");
this->close(); this->server->close();
this->setThreadStateAndEmitEvent(ThreadState::STOPPED); this->setThreadStateAndEmitEvent(ThreadState::STOPPED);
EventManager::deregisterListener(this->eventListener->getId()); EventManager::deregisterListener(this->eventListener->getId());
} }

View File

@@ -1,8 +1,9 @@
#pragma once #pragma once
#include <cstdint>
#include <map> #include <map>
#include <functional> #include <functional>
#include <cstdint> #include <memory>
#include "src/TargetController/TargetControllerConsole.hpp" #include "src/TargetController/TargetControllerConsole.hpp"
#include "src/EventManager/Events/Events.hpp" #include "src/EventManager/Events/Events.hpp"
@@ -14,6 +15,8 @@
#include "src/Targets/TargetRegister.hpp" #include "src/Targets/TargetRegister.hpp"
#include "src/Targets/TargetBreakpoint.hpp" #include "src/Targets/TargetBreakpoint.hpp"
#include "ServerInterface.hpp"
namespace Bloom::DebugServers namespace Bloom::DebugServers
{ {
/** /**
@@ -28,28 +31,16 @@ namespace Bloom::DebugServers
class DebugServer: public Thread class DebugServer: public Thread
{ {
public: public:
explicit DebugServer( explicit DebugServer(const DebugServerConfig& debugServerConfig);
const ProjectConfig& projectConfig,
const EnvironmentConfig& environmentConfig,
const DebugServerConfig& debugServerConfig
)
: projectConfig(projectConfig)
, environmentConfig(environmentConfig)
, debugServerConfig(debugServerConfig)
{};
/** /**
* Entry point for the DebugServer. This must called from a dedicated thread. * Entry point for the DebugServer. This must called from a dedicated thread.
*/ */
void run(); void run();
virtual std::string getName() const = 0;
protected: protected:
EventListenerPointer eventListener = std::make_shared<EventListener>("DebugServerEventListener"); EventListenerPointer eventListener = std::make_shared<EventListener>("DebugServerEventListener");
ProjectConfig projectConfig;
EnvironmentConfig environmentConfig;
DebugServerConfig debugServerConfig; DebugServerConfig debugServerConfig;
TargetControllerConsole targetControllerConsole = TargetControllerConsole(*(this->eventListener)); TargetControllerConsole targetControllerConsole = TargetControllerConsole(*(this->eventListener));
@@ -57,26 +48,13 @@ namespace Bloom::DebugServers
/** /**
* Enables the interruption of any blocking file IO. * Enables the interruption of any blocking file IO.
*/ */
std::shared_ptr<EventNotifier> interruptEventNotifier = nullptr; EventNotifier interruptEventNotifier = EventNotifier();
Targets::TargetDescriptor targetDescriptor;
/**
* Called on startup of the DebugServer thread. Derived classes should implement any initialisation work here.
*/
virtual void init() = 0;
/**
* Called repeatedly in an infinite loop when the DebugServer is running.
*/
virtual void serve() = 0;
/**
* Called on shutdown of the debug server.
*/
virtual void close() = 0;
private: private:
std::unique_ptr<ServerInterface> server = nullptr;
std::map<std::string, std::function<std::unique_ptr<ServerInterface>()>> getAvailableServersByName();
/** /**
* Prepares the debug server thread and then calls init(). * Prepares the debug server thread and then calls init().
* *

View File

@@ -7,9 +7,18 @@ namespace Bloom::DebugServers::Gdb::AvrGdb
using Bloom::Targets::TargetRegisterDescriptor; using Bloom::Targets::TargetRegisterDescriptor;
using Bloom::Targets::TargetRegisterType; using Bloom::Targets::TargetRegisterType;
AvrGdbRsp::AvrGdbRsp(
const DebugServerConfig& debugServerConfig,
EventListener& eventListener
)
: GdbRspDebugServer(debugServerConfig, eventListener)
{}
void AvrGdbRsp::init() { void AvrGdbRsp::init() {
DebugServers::Gdb::GdbRspDebugServer::init(); DebugServers::Gdb::GdbRspDebugServer::init();
this->gdbTargetDescriptor = TargetDescriptor(this->targetDescriptor); this->gdbTargetDescriptor = TargetDescriptor(
this->targetControllerConsole.getTargetDescriptor()
);
} }
} }

View File

@@ -26,11 +26,10 @@ namespace Bloom::DebugServers::Gdb::AvrGdb
class AvrGdbRsp: public GdbRspDebugServer class AvrGdbRsp: public GdbRspDebugServer
{ {
public: public:
explicit AvrGdbRsp( AvrGdbRsp(
const ProjectConfig& projectConfig, const DebugServerConfig& debugServerConfig,
const EnvironmentConfig& environmentConfig, EventListener& eventListener
const DebugServerConfig& debugServerConfig );
): GdbRspDebugServer(projectConfig, environmentConfig, debugServerConfig) {};
std::string getName() const override { std::string getName() const override {
return "AVR GDB Remote Serial Protocol Debug Server"; return "AVR GDB Remote Serial Protocol Debug Server";

View File

@@ -9,26 +9,30 @@
#include "Exceptions/ClientNotSupported.hpp" #include "Exceptions/ClientNotSupported.hpp"
#include "Exceptions/ClientCommunicationError.hpp" #include "Exceptions/ClientCommunicationError.hpp"
#include "Exceptions/DebugSessionAborted.hpp" #include "Exceptions/DebugSessionAborted.hpp"
#include "src/Exceptions/Exception.hpp" #include "src/Exceptions/Exception.hpp"
#include "src/Exceptions/InvalidConfig.hpp" #include "src/Exceptions/InvalidConfig.hpp"
#include "src/Exceptions/DebugServerInterrupted.hpp"
#include "ResponsePackets/TargetStopped.hpp"
namespace Bloom::DebugServers::Gdb namespace Bloom::DebugServers::Gdb
{ {
using namespace CommandPackets;
using namespace ResponsePackets;
using namespace Exceptions; using namespace Exceptions;
using namespace Bloom::Events;
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
using Bloom::Targets::TargetRegister; GdbRspDebugServer::GdbRspDebugServer(
using Bloom::Targets::TargetRegisterType; const DebugServerConfig& debugServerConfig,
using Bloom::Targets::TargetRegisterDescriptor; EventListener& eventListener
using Bloom::Targets::TargetRegisterDescriptors; )
using Bloom::Targets::TargetBreakpoint; : debugServerConfig(GdbDebugServerConfig(debugServerConfig))
, eventListener(eventListener)
, interruptEventNotifier(eventListener.getInterruptEventNotifier())
{
assert(this->interruptEventNotifier != nullptr && this->interruptEventNotifier->isInitialised());
}
void GdbRspDebugServer::init() { void GdbRspDebugServer::init() {
this->debugServerConfig = GdbDebugServerConfig(DebugServer::debugServerConfig);
this->socketAddress.sin_family = AF_INET; this->socketAddress.sin_family = AF_INET;
this->socketAddress.sin_port = htons(this->debugServerConfig->listeningPortNumber); this->socketAddress.sin_port = htons(this->debugServerConfig->listeningPortNumber);
@@ -83,24 +87,22 @@ namespace Bloom::DebugServers::Gdb
throw Exception("Failed epoll_ctl server socket"); throw Exception("Failed epoll_ctl server socket");
} }
if (this->interruptEventNotifier != nullptr) { const auto interruptFileDescriptor = this->interruptEventNotifier->getFileDescriptor();
auto interruptFileDescriptor = this->interruptEventNotifier->getFileDescriptor(); event.events = EPOLLIN;
event.events = EPOLLIN; event.data.fd = interruptFileDescriptor;
event.data.fd = interruptFileDescriptor;
if (::epoll_ctl(this->eventFileDescriptor, EPOLL_CTL_ADD, interruptFileDescriptor, &event) != 0) { if (::epoll_ctl(this->eventFileDescriptor, EPOLL_CTL_ADD, interruptFileDescriptor, &event) != 0) {
throw Exception("Failed epoll_ctl interrupt event fd"); throw Exception("Failed epoll_ctl interrupt event fd");
}
} }
Logger::info("GDB RSP address: " + this->debugServerConfig->listeningAddress); Logger::info("GDB RSP address: " + this->debugServerConfig->listeningAddress);
Logger::info("GDB RSP port: " + std::to_string(this->debugServerConfig->listeningPortNumber)); Logger::info("GDB RSP port: " + std::to_string(this->debugServerConfig->listeningPortNumber));
this->eventListener->registerCallbackForEventType<Events::TargetControllerStateReported>( this->eventListener.registerCallbackForEventType<Events::TargetControllerStateReported>(
std::bind(&GdbRspDebugServer::onTargetControllerStateReported, this, std::placeholders::_1) std::bind(&GdbRspDebugServer::onTargetControllerStateReported, this, std::placeholders::_1)
); );
this->eventListener->registerCallbackForEventType<Events::TargetExecutionStopped>( this->eventListener.registerCallbackForEventType<Events::TargetExecutionStopped>(
std::bind(&GdbRspDebugServer::onTargetExecutionStopped, this, std::placeholders::_1) std::bind(&GdbRspDebugServer::onTargetExecutionStopped, this, std::placeholders::_1)
); );
} }
@@ -113,7 +115,7 @@ namespace Bloom::DebugServers::Gdb
} }
} }
void GdbRspDebugServer::serve() { void GdbRspDebugServer::run() {
try { try {
if (!this->activeDebugSession.has_value()) { if (!this->activeDebugSession.has_value()) {
Logger::info("Waiting for GDB RSP connection"); Logger::info("Waiting for GDB RSP connection");
@@ -131,6 +133,7 @@ namespace Bloom::DebugServers::Gdb
this->activeDebugSession.emplace( this->activeDebugSession.emplace(
DebugSession(connection.value(), this->getGdbTargetDescriptor()) DebugSession(connection.value(), this->getGdbTargetDescriptor())
); );
EventManager::triggerEvent(std::make_shared<Events::DebugSessionStarted>()); EventManager::triggerEvent(std::make_shared<Events::DebugSessionStarted>());
/* /*
@@ -205,7 +208,7 @@ namespace Bloom::DebugServers::Gdb
} }
} }
return Connection(this->interruptEventNotifier); return Connection(*(this->interruptEventNotifier));
} }
return std::nullopt; return std::nullopt;
@@ -229,7 +232,9 @@ namespace Bloom::DebugServers::Gdb
void GdbRspDebugServer::onTargetExecutionStopped(const Events::TargetExecutionStopped&) { void GdbRspDebugServer::onTargetExecutionStopped(const Events::TargetExecutionStopped&) {
if (this->activeDebugSession.has_value() && this->activeDebugSession->waitingForBreak) { if (this->activeDebugSession.has_value() && this->activeDebugSession->waitingForBreak) {
this->activeDebugSession->connection.writePacket(TargetStopped(Signal::TRAP)); this->activeDebugSession->connection.writePacket(
ResponsePackets::TargetStopped(Signal::TRAP)
);
this->activeDebugSession->waitingForBreak = false; this->activeDebugSession->waitingForBreak = false;
} }
} }

View File

@@ -1,14 +1,17 @@
#pragma once #pragma once
#include <cstdint>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <vector> #include <vector>
#include <queue> #include <queue>
#include <cstdint> #include <optional>
#include "src/DebugServers/DebugServer.hpp" #include "src/DebugServers/ServerInterface.hpp"
#include "GdbDebugServerConfig.hpp" #include "GdbDebugServerConfig.hpp"
#include "src/EventManager/EventListener.hpp"
#include "src/TargetController/TargetControllerConsole.hpp"
#include "Connection.hpp" #include "Connection.hpp"
#include "TargetDescriptor.hpp" #include "TargetDescriptor.hpp"
@@ -18,15 +21,11 @@
#include "Feature.hpp" #include "Feature.hpp"
#include "CommandPackets/CommandPacketFactory.hpp" #include "CommandPackets/CommandPacketFactory.hpp"
#include "src/Helpers/EventNotifier.hpp" #include "src/EventManager/Events/TargetControllerStateReported.hpp"
#include "src/EventManager/Events/TargetExecutionStopped.hpp"
#include "src/Helpers/BiMap.hpp" #include "src/Helpers/BiMap.hpp"
#include "src/Targets/TargetRegister.hpp"
// Response packets
#include "ResponsePackets/SupportedFeaturesResponse.hpp"
#include "ResponsePackets/TargetStopped.hpp"
namespace Bloom::DebugServers::Gdb namespace Bloom::DebugServers::Gdb
{ {
/** /**
@@ -40,22 +39,44 @@ namespace Bloom::DebugServers::Gdb
* *
* @TODO: This could do with some cleaning. * @TODO: This could do with some cleaning.
*/ */
class GdbRspDebugServer: public DebugServer class GdbRspDebugServer: public ServerInterface
{ {
public: public:
explicit GdbRspDebugServer( explicit GdbRspDebugServer(
const ProjectConfig& projectConfig, const DebugServerConfig& debugServerConfig,
const EnvironmentConfig& environmentConfig, EventListener& eventListener
const DebugServerConfig& debugServerConfig );
): DebugServer(projectConfig, environmentConfig, debugServerConfig) {};
std::string getName() const override { [[nodiscard]] std::string getName() const override {
return "GDB Remote Serial Protocol DebugServer"; return "GDB Remote Serial Protocol DebugServer";
}; };
/**
* Prepares the GDB server for listing on the selected address and port.
*/
void init() override;
/**
* Terminates any active debug session and closes the listening socket.
*/
void close() override;
/**
* Waits for a connection from a GDB client or services an active one.
*
* This function will return when any blocking operation is interrupted via this->interruptEventNotifier.
*/
void run() override;
protected: protected:
std::optional<GdbDebugServerConfig> debugServerConfig; std::optional<GdbDebugServerConfig> debugServerConfig;
EventListener& eventListener;
EventNotifier* interruptEventNotifier = nullptr;
TargetControllerConsole targetControllerConsole = TargetControllerConsole(this->eventListener);
/** /**
* Listening socket address * Listening socket address
*/ */
@@ -84,21 +105,6 @@ namespace Bloom::DebugServers::Gdb
std::optional<DebugSession> activeDebugSession; std::optional<DebugSession> activeDebugSession;
/**
* Prepares the GDB server for listing on the selected address and port.
*/
void init() override;
/**
* Closes any client connection as well as the listening socket file descriptor.
*/
void close() override;
/**
* See DebugServer::serve()
*/
void serve() override;
/** /**
* Waits for a GDB client to connect on the listening socket. * Waits for a GDB client to connect on the listening socket.
* *
@@ -110,7 +116,6 @@ namespace Bloom::DebugServers::Gdb
virtual const TargetDescriptor& getGdbTargetDescriptor() = 0; virtual const TargetDescriptor& getGdbTargetDescriptor() = 0;
void onTargetControllerStateReported(const Events::TargetControllerStateReported& event); void onTargetControllerStateReported(const Events::TargetControllerStateReported& event);
/** /**

View File

@@ -0,0 +1,35 @@
#pragma once
#include <string>
namespace Bloom::DebugServers
{
class ServerInterface
{
public:
/**
* Should return the name of the server.
*
* @return
*/
[[nodiscard]] virtual std::string getName() const = 0;
/**
* Called on startup of the DebugServerComponent. The server should implement any initialisation work here.
*/
virtual void init() = 0;
/**
* Called repeatedly in an infinite loop when the DebugServerComponent is running. The server should serve
* from here.
*
* This function should return when any blocking operation is interrupted via an EventNotifier instance.
*/
virtual void run() = 0;
/**
* Called on shutdown of the DebugServerComponent.
*/
virtual void close() = 0;
};
}