From 934c4b2820ea9ee105f89a381041b83c6f9cbd5f Mon Sep 17 00:00:00 2001 From: Nav Date: Sun, 27 Mar 2022 18:32:13 +0100 Subject: [PATCH] Created new ServerInterface class and refactored the AVR GDB RSP debug server into an implementation of ServerInterface --- src/Application.cpp | 13 +--- src/Application.hpp | 25 +------ src/DebugServers/DebugServer.cpp | 40 +++++++++-- src/DebugServers/DebugServer.hpp | 42 +++--------- src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.cpp | 11 ++- src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.hpp | 9 ++- src/DebugServers/GdbRsp/GdbRspDebugServer.cpp | 49 ++++++++------ src/DebugServers/GdbRsp/GdbRspDebugServer.hpp | 67 ++++++++++--------- src/DebugServers/ServerInterface.hpp | 35 ++++++++++ 9 files changed, 159 insertions(+), 132 deletions(-) create mode 100644 src/DebugServers/ServerInterface.hpp diff --git a/src/Application.cpp b/src/Application.cpp index 907de8be..2f99fbbc 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -390,15 +390,9 @@ namespace Bloom } void Application::startDebugServer() { - auto supportedDebugServers = this->getSupportedDebugServers(); - if (!supportedDebugServers.contains(this->debugServerConfig->name)) { - throw Exceptions::InvalidConfig( - "DebugServer \"" + this->debugServerConfig->name + "\" not found." - ); - } - - this->debugServer = supportedDebugServers.at(this->debugServerConfig->name)(); - Logger::info("Selected DebugServer: " + this->debugServer->getName()); + this->debugServer = std::make_unique( + this->debugServerConfig.value() + ); this->debugServerThread = std::thread( &DebugServers::DebugServer::run, @@ -414,7 +408,6 @@ namespace Bloom void Application::stopDebugServer() { if (this->debugServer == nullptr) { - // DebugServer hasn't been resolved yet. return; } diff --git a/src/Application.hpp b/src/Application.hpp index a6217c5c..ce821336 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -10,7 +10,7 @@ #include "src/Helpers/Thread.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/SignalHandler/SignalHandler.hpp" @@ -37,29 +37,6 @@ namespace Bloom 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()>> { - { - "avr-gdb-rsp", - [this] () -> std::unique_ptr { - return std::make_unique( - this->projectConfig.value(), - this->environmentConfig.value(), - this->debugServerConfig.value() - ); - } - }, - }; - }; - /** * Main entry-point for the Bloom program. * diff --git a/src/DebugServers/DebugServer.cpp b/src/DebugServers/DebugServer.cpp index 43654df3..2ea7ff65 100644 --- a/src/DebugServers/DebugServer.cpp +++ b/src/DebugServers/DebugServer.cpp @@ -2,6 +2,9 @@ #include +// Debug server implementations +#include "GdbRsp/AvrGdb/AvrGdbRsp.hpp" + #include "src/Exceptions/InvalidConfig.hpp" #include "src/Logger/Logger.hpp" @@ -9,6 +12,10 @@ namespace Bloom::DebugServers { using namespace Bloom::Events; + DebugServer::DebugServer(const DebugServerConfig& debugServerConfig) + : debugServerConfig(debugServerConfig) + {} + void DebugServer::run() { try { this->startup(); @@ -16,7 +23,7 @@ namespace Bloom::DebugServers Logger::info("DebugServer ready"); while (this->getThreadState() == ThreadState::READY) { - this->serve(); + this->server->run(); this->eventListener->dispatchCurrentEvents(); } } catch (const std::exception& exception) { @@ -26,23 +33,42 @@ namespace Bloom::DebugServers this->shutdown(); } + std::map()>> DebugServer::getAvailableServersByName() { + return std::map()>> { + { + "avr-gdb-rsp", + [this] () -> std::unique_ptr { + return std::make_unique( + this->debugServerConfig, + *(this->eventListener.get()) + ); + } + }, + }; + } void DebugServer::startup() { this->setName("DS"); Logger::info("Starting DebugServer"); EventManager::registerListener(this->eventListener); - - this->interruptEventNotifier = std::make_shared(); - this->eventListener->setInterruptEventNotifier(this->interruptEventNotifier); + this->eventListener->setInterruptEventNotifier(&this->interruptEventNotifier); // Register event handlers this->eventListener->registerCallbackForEventType( 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); } @@ -55,7 +81,7 @@ namespace Bloom::DebugServers this->setThreadState(ThreadState::SHUTDOWN_INITIATED); Logger::info("Shutting down DebugServer"); - this->close(); + this->server->close(); this->setThreadStateAndEmitEvent(ThreadState::STOPPED); EventManager::deregisterListener(this->eventListener->getId()); } diff --git a/src/DebugServers/DebugServer.hpp b/src/DebugServers/DebugServer.hpp index b546c9fa..8d84df9e 100644 --- a/src/DebugServers/DebugServer.hpp +++ b/src/DebugServers/DebugServer.hpp @@ -1,8 +1,9 @@ #pragma once +#include #include #include -#include +#include #include "src/TargetController/TargetControllerConsole.hpp" #include "src/EventManager/Events/Events.hpp" @@ -14,6 +15,8 @@ #include "src/Targets/TargetRegister.hpp" #include "src/Targets/TargetBreakpoint.hpp" +#include "ServerInterface.hpp" + namespace Bloom::DebugServers { /** @@ -28,28 +31,16 @@ namespace Bloom::DebugServers class DebugServer: public Thread { public: - explicit DebugServer( - const ProjectConfig& projectConfig, - const EnvironmentConfig& environmentConfig, - const DebugServerConfig& debugServerConfig - ) - : projectConfig(projectConfig) - , environmentConfig(environmentConfig) - , debugServerConfig(debugServerConfig) - {}; + explicit DebugServer(const DebugServerConfig& debugServerConfig); /** * Entry point for the DebugServer. This must called from a dedicated thread. */ void run(); - virtual std::string getName() const = 0; - protected: EventListenerPointer eventListener = std::make_shared("DebugServerEventListener"); - ProjectConfig projectConfig; - EnvironmentConfig environmentConfig; DebugServerConfig debugServerConfig; TargetControllerConsole targetControllerConsole = TargetControllerConsole(*(this->eventListener)); @@ -57,26 +48,13 @@ namespace Bloom::DebugServers /** * Enables the interruption of any blocking file IO. */ - std::shared_ptr interruptEventNotifier = nullptr; - - 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; + EventNotifier interruptEventNotifier = EventNotifier(); private: + std::unique_ptr server = nullptr; + + std::map()>> getAvailableServersByName(); + /** * Prepares the debug server thread and then calls init(). * diff --git a/src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.cpp b/src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.cpp index 5299d040..f3c88e9f 100644 --- a/src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.cpp +++ b/src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.cpp @@ -7,9 +7,18 @@ namespace Bloom::DebugServers::Gdb::AvrGdb using Bloom::Targets::TargetRegisterDescriptor; using Bloom::Targets::TargetRegisterType; + AvrGdbRsp::AvrGdbRsp( + const DebugServerConfig& debugServerConfig, + EventListener& eventListener + ) + : GdbRspDebugServer(debugServerConfig, eventListener) + {} + void AvrGdbRsp::init() { DebugServers::Gdb::GdbRspDebugServer::init(); - this->gdbTargetDescriptor = TargetDescriptor(this->targetDescriptor); + this->gdbTargetDescriptor = TargetDescriptor( + this->targetControllerConsole.getTargetDescriptor() + ); } } diff --git a/src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.hpp b/src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.hpp index 72751f24..f6c231b2 100644 --- a/src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.hpp +++ b/src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.hpp @@ -26,11 +26,10 @@ namespace Bloom::DebugServers::Gdb::AvrGdb class AvrGdbRsp: public GdbRspDebugServer { public: - explicit AvrGdbRsp( - const ProjectConfig& projectConfig, - const EnvironmentConfig& environmentConfig, - const DebugServerConfig& debugServerConfig - ): GdbRspDebugServer(projectConfig, environmentConfig, debugServerConfig) {}; + AvrGdbRsp( + const DebugServerConfig& debugServerConfig, + EventListener& eventListener + ); std::string getName() const override { return "AVR GDB Remote Serial Protocol Debug Server"; diff --git a/src/DebugServers/GdbRsp/GdbRspDebugServer.cpp b/src/DebugServers/GdbRsp/GdbRspDebugServer.cpp index 815b8f70..ef10fe66 100644 --- a/src/DebugServers/GdbRsp/GdbRspDebugServer.cpp +++ b/src/DebugServers/GdbRsp/GdbRspDebugServer.cpp @@ -9,26 +9,30 @@ #include "Exceptions/ClientNotSupported.hpp" #include "Exceptions/ClientCommunicationError.hpp" #include "Exceptions/DebugSessionAborted.hpp" + #include "src/Exceptions/Exception.hpp" #include "src/Exceptions/InvalidConfig.hpp" +#include "src/Exceptions/DebugServerInterrupted.hpp" + +#include "ResponsePackets/TargetStopped.hpp" namespace Bloom::DebugServers::Gdb { - using namespace CommandPackets; - using namespace ResponsePackets; using namespace Exceptions; - using namespace Bloom::Events; using namespace Bloom::Exceptions; - using Bloom::Targets::TargetRegister; - using Bloom::Targets::TargetRegisterType; - using Bloom::Targets::TargetRegisterDescriptor; - using Bloom::Targets::TargetRegisterDescriptors; - using Bloom::Targets::TargetBreakpoint; + GdbRspDebugServer::GdbRspDebugServer( + const DebugServerConfig& debugServerConfig, + EventListener& eventListener + ) + : debugServerConfig(GdbDebugServerConfig(debugServerConfig)) + , eventListener(eventListener) + , interruptEventNotifier(eventListener.getInterruptEventNotifier()) + { + assert(this->interruptEventNotifier != nullptr && this->interruptEventNotifier->isInitialised()); + } void GdbRspDebugServer::init() { - this->debugServerConfig = GdbDebugServerConfig(DebugServer::debugServerConfig); - this->socketAddress.sin_family = AF_INET; this->socketAddress.sin_port = htons(this->debugServerConfig->listeningPortNumber); @@ -83,24 +87,22 @@ namespace Bloom::DebugServers::Gdb throw Exception("Failed epoll_ctl server socket"); } - if (this->interruptEventNotifier != nullptr) { - auto interruptFileDescriptor = this->interruptEventNotifier->getFileDescriptor(); - event.events = EPOLLIN; - event.data.fd = interruptFileDescriptor; + const auto interruptFileDescriptor = this->interruptEventNotifier->getFileDescriptor(); + event.events = EPOLLIN; + event.data.fd = interruptFileDescriptor; - if (::epoll_ctl(this->eventFileDescriptor, EPOLL_CTL_ADD, interruptFileDescriptor, &event) != 0) { - throw Exception("Failed epoll_ctl interrupt event fd"); - } + if (::epoll_ctl(this->eventFileDescriptor, EPOLL_CTL_ADD, interruptFileDescriptor, &event) != 0) { + throw Exception("Failed epoll_ctl interrupt event fd"); } Logger::info("GDB RSP address: " + this->debugServerConfig->listeningAddress); Logger::info("GDB RSP port: " + std::to_string(this->debugServerConfig->listeningPortNumber)); - this->eventListener->registerCallbackForEventType( + this->eventListener.registerCallbackForEventType( std::bind(&GdbRspDebugServer::onTargetControllerStateReported, this, std::placeholders::_1) ); - this->eventListener->registerCallbackForEventType( + this->eventListener.registerCallbackForEventType( std::bind(&GdbRspDebugServer::onTargetExecutionStopped, this, std::placeholders::_1) ); } @@ -113,7 +115,7 @@ namespace Bloom::DebugServers::Gdb } } - void GdbRspDebugServer::serve() { + void GdbRspDebugServer::run() { try { if (!this->activeDebugSession.has_value()) { Logger::info("Waiting for GDB RSP connection"); @@ -131,6 +133,7 @@ namespace Bloom::DebugServers::Gdb this->activeDebugSession.emplace( DebugSession(connection.value(), this->getGdbTargetDescriptor()) ); + EventManager::triggerEvent(std::make_shared()); /* @@ -205,7 +208,7 @@ namespace Bloom::DebugServers::Gdb } } - return Connection(this->interruptEventNotifier); + return Connection(*(this->interruptEventNotifier)); } return std::nullopt; @@ -229,7 +232,9 @@ namespace Bloom::DebugServers::Gdb void GdbRspDebugServer::onTargetExecutionStopped(const Events::TargetExecutionStopped&) { 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; } } diff --git a/src/DebugServers/GdbRsp/GdbRspDebugServer.hpp b/src/DebugServers/GdbRsp/GdbRspDebugServer.hpp index d70698f0..256507e0 100644 --- a/src/DebugServers/GdbRsp/GdbRspDebugServer.hpp +++ b/src/DebugServers/GdbRsp/GdbRspDebugServer.hpp @@ -1,14 +1,17 @@ #pragma once +#include #include #include #include #include -#include +#include -#include "src/DebugServers/DebugServer.hpp" +#include "src/DebugServers/ServerInterface.hpp" #include "GdbDebugServerConfig.hpp" +#include "src/EventManager/EventListener.hpp" +#include "src/TargetController/TargetControllerConsole.hpp" #include "Connection.hpp" #include "TargetDescriptor.hpp" @@ -18,15 +21,11 @@ #include "Feature.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/Targets/TargetRegister.hpp" - -// Response packets -#include "ResponsePackets/SupportedFeaturesResponse.hpp" -#include "ResponsePackets/TargetStopped.hpp" - namespace Bloom::DebugServers::Gdb { /** @@ -40,22 +39,44 @@ namespace Bloom::DebugServers::Gdb * * @TODO: This could do with some cleaning. */ - class GdbRspDebugServer: public DebugServer + class GdbRspDebugServer: public ServerInterface { public: explicit GdbRspDebugServer( - const ProjectConfig& projectConfig, - const EnvironmentConfig& environmentConfig, - const DebugServerConfig& debugServerConfig - ): DebugServer(projectConfig, environmentConfig, debugServerConfig) {}; + const DebugServerConfig& debugServerConfig, + EventListener& eventListener + ); - std::string getName() const override { + [[nodiscard]] std::string getName() const override { 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: std::optional debugServerConfig; + EventListener& eventListener; + + EventNotifier* interruptEventNotifier = nullptr; + + TargetControllerConsole targetControllerConsole = TargetControllerConsole(this->eventListener); + /** * Listening socket address */ @@ -84,21 +105,6 @@ namespace Bloom::DebugServers::Gdb std::optional 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. * @@ -110,7 +116,6 @@ namespace Bloom::DebugServers::Gdb virtual const TargetDescriptor& getGdbTargetDescriptor() = 0; - void onTargetControllerStateReported(const Events::TargetControllerStateReported& event); /** diff --git a/src/DebugServers/ServerInterface.hpp b/src/DebugServers/ServerInterface.hpp new file mode 100644 index 00000000..478f29a8 --- /dev/null +++ b/src/DebugServers/ServerInterface.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include + +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; + }; +}