diff --git a/src/DebugServer/Gdb/GdbRspDebugServer.cpp b/src/DebugServer/Gdb/GdbRspDebugServer.cpp index 5dd360f8..be6d11b3 100644 --- a/src/DebugServer/Gdb/GdbRspDebugServer.cpp +++ b/src/DebugServer/Gdb/GdbRspDebugServer.cpp @@ -1,7 +1,6 @@ #include "GdbRspDebugServer.hpp" #include -#include #include "src/Logger/Logger.hpp" @@ -48,17 +47,17 @@ namespace Bloom::DebugServer::Gdb void GdbRspDebugServer::init() { this->socketAddress.sin_family = AF_INET; - this->socketAddress.sin_port = htons(this->debugServerConfig->listeningPortNumber); + this->socketAddress.sin_port = htons(this->debugServerConfig.listeningPortNumber); if (::inet_pton( AF_INET, - this->debugServerConfig->listeningAddress.c_str(), + this->debugServerConfig.listeningAddress.c_str(), &(this->socketAddress.sin_addr) ) == 0 ) { // Invalid IP address throw InvalidConfig( - "Invalid IP address provided in config file: (\"" + this->debugServerConfig->listeningAddress + "Invalid IP address provided in config file: (\"" + this->debugServerConfig.listeningAddress + "\")" ); } @@ -69,12 +68,14 @@ namespace Bloom::DebugServer::Gdb throw Exception("Failed to create socket file descriptor."); } + const auto enableReuseAddressSocketOption = 1; + if (::setsockopt( socketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, - &(this->enableReuseAddressSocketOption), - sizeof(this->enableReuseAddressSocketOption) + &(enableReuseAddressSocketOption), + sizeof(enableReuseAddressSocketOption) ) < 0 ) { Logger::error("Failed to set socket SO_REUSEADDR option."); @@ -87,13 +88,13 @@ namespace Bloom::DebugServer::Gdb ) < 0 ) { throw Exception("Failed to bind address. The selected port number (" - + std::to_string(this->debugServerConfig->listeningPortNumber) + ") may be in use."); + + std::to_string(this->debugServerConfig.listeningPortNumber) + ") may be in use."); } this->serverSocketFileDescriptor = socketFileDescriptor; this->epollInstance.addEntry( - this->serverSocketFileDescriptor, + this->serverSocketFileDescriptor.value(), static_cast(EpollEvent::READ_READY) ); @@ -102,8 +103,8 @@ namespace Bloom::DebugServer::Gdb static_cast(EpollEvent::READ_READY) ); - Logger::info("GDB RSP address: " + this->debugServerConfig->listeningAddress); - Logger::info("GDB RSP port: " + std::to_string(this->debugServerConfig->listeningPortNumber)); + Logger::info("GDB RSP address: " + this->debugServerConfig.listeningAddress); + Logger::info("GDB RSP port: " + std::to_string(this->debugServerConfig.listeningPortNumber)); this->eventListener.registerCallbackForEventType( std::bind(&GdbRspDebugServer::onTargetControllerStateReported, this, std::placeholders::_1) @@ -117,8 +118,8 @@ namespace Bloom::DebugServer::Gdb void GdbRspDebugServer::close() { this->terminateActiveDebugSession(); - if (this->serverSocketFileDescriptor > 0) { - ::close(this->serverSocketFileDescriptor); + if (this->serverSocketFileDescriptor.has_value()) { + ::close(this->serverSocketFileDescriptor.value()); } } @@ -191,7 +192,7 @@ namespace Bloom::DebugServer::Gdb } std::optional GdbRspDebugServer::waitForConnection() { - if (::listen(this->serverSocketFileDescriptor, 3) != 0) { + if (::listen(this->serverSocketFileDescriptor.value(), 3) != 0) { throw Exception("Failed to listen on server socket"); } @@ -205,7 +206,10 @@ namespace Bloom::DebugServer::Gdb return std::nullopt; } - return std::make_optional(this->serverSocketFileDescriptor, *(this->interruptEventNotifier)); + return std::make_optional( + this->serverSocketFileDescriptor.value(), + *(this->interruptEventNotifier) + ); } std::unique_ptr GdbRspDebugServer::waitForCommandPacket() { @@ -266,12 +270,14 @@ namespace Bloom::DebugServer::Gdb } void GdbRspDebugServer::terminateActiveDebugSession() { - if (this->activeDebugSession.has_value()) { - this->activeDebugSession->terminate(); - this->activeDebugSession = std::nullopt; - - EventManager::triggerEvent(std::make_shared()); + if (!this->activeDebugSession.has_value()) { + return; } + + this->activeDebugSession->terminate(); + this->activeDebugSession = std::nullopt; + + EventManager::triggerEvent(std::make_shared()); } void GdbRspDebugServer::onTargetControllerStateReported(const Events::TargetControllerStateReported& event) { diff --git a/src/DebugServer/Gdb/GdbRspDebugServer.hpp b/src/DebugServer/Gdb/GdbRspDebugServer.hpp index deaaf02c..5406a484 100644 --- a/src/DebugServer/Gdb/GdbRspDebugServer.hpp +++ b/src/DebugServer/Gdb/GdbRspDebugServer.hpp @@ -25,20 +25,16 @@ #include "src/EventManager/Events/TargetControllerStateReported.hpp" #include "src/EventManager/Events/TargetExecutionStopped.hpp" -#include "src/Helpers/BiMap.hpp" - namespace Bloom::DebugServer::Gdb { /** - * The GdbRspDebugServer is an implementation of a GDB server using the GDB Remote Serial Protocol. + * The GdbRspDebugServer is an implementation of the GDB Remote Serial Protocol. * - * This DebugServer employs TCP/IP sockets to interface with GDB clients. The listening address can be configured - * in the user's project config file. + * This server employs TCP/IP sockets to interface with GDB clients. The listening address and port can be + * configured in the user's project config file. * - * See https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html for more info on the GDB Remote - * Serial Protocol. - * - * @TODO: This could do with some cleaning. + * See https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html for more info on the GDB Remote Serial + * Protocol. */ class GdbRspDebugServer: public ServerInterface { @@ -48,6 +44,15 @@ namespace Bloom::DebugServer::Gdb EventListener& eventListener ); + GdbRspDebugServer() = delete; + virtual ~GdbRspDebugServer() = default; + + GdbRspDebugServer(const GdbRspDebugServer& other) = delete; + GdbRspDebugServer(GdbRspDebugServer&& other) = delete; + + GdbRspDebugServer& operator = (const GdbRspDebugServer& other) = delete; + GdbRspDebugServer& operator = (GdbRspDebugServer&& other) = delete; + [[nodiscard]] std::string getName() const override { return "GDB Remote Serial Protocol DebugServer"; }; @@ -70,24 +75,25 @@ namespace Bloom::DebugServer::Gdb void run() override; protected: - std::optional debugServerConfig; + /** + * User project configuration specific to the GDB RSP debug server. + */ + GdbDebugServerConfig debugServerConfig; + /** + * The DebugServerComponent's event listener. + */ EventListener& eventListener; + /** + * EventNotifier object for interrupting blocking I/O operations. + * + * Extracted from this->eventListener. + * + * See documentation in src/DebugServer/README.md for more. + */ EventNotifier* interruptEventNotifier = nullptr; - TargetControllerConsole targetControllerConsole = TargetControllerConsole(this->eventListener); - - /** - * Listening socket address - */ - struct sockaddr_in socketAddress = {}; - - /** - * Listening socket file descriptor - */ - int serverSocketFileDescriptor = -1; - /** * When waiting for a connection, we don't listen on the this->serverSocketFileDescriptor directly. Instead, * we use an EpollInstance to monitor both this->serverSocketFileDescriptor and this->interruptEventNotifier. @@ -102,9 +108,21 @@ namespace Bloom::DebugServer::Gdb EpollInstance epollInstance = EpollInstance(); /** - * SO_REUSEADDR option value for listening socket. + * Passed to command handlers (see CommandPacket::handle()). + * + * See documentation in src/DebugServer/Gdb/README.md for more on how GDB commands are processed. */ - int enableReuseAddressSocketOption = 1; + TargetControllerConsole targetControllerConsole = TargetControllerConsole(this->eventListener); + + /** + * Listening socket address + */ + struct sockaddr_in socketAddress = {}; + + /** + * Listening socket file descriptor + */ + std::optional serverSocketFileDescriptor; /** * When a connection with a GDB client is established, a new instance of the DebugSession class is created and