Tidied GDB RSP debug server
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
#include "GdbRspDebugServer.hpp"
|
#include "GdbRspDebugServer.hpp"
|
||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/epoll.h>
|
|
||||||
|
|
||||||
#include "src/Logger/Logger.hpp"
|
#include "src/Logger/Logger.hpp"
|
||||||
|
|
||||||
@@ -48,17 +47,17 @@ namespace Bloom::DebugServer::Gdb
|
|||||||
|
|
||||||
void GdbRspDebugServer::init() {
|
void GdbRspDebugServer::init() {
|
||||||
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);
|
||||||
|
|
||||||
if (::inet_pton(
|
if (::inet_pton(
|
||||||
AF_INET,
|
AF_INET,
|
||||||
this->debugServerConfig->listeningAddress.c_str(),
|
this->debugServerConfig.listeningAddress.c_str(),
|
||||||
&(this->socketAddress.sin_addr)
|
&(this->socketAddress.sin_addr)
|
||||||
) == 0
|
) == 0
|
||||||
) {
|
) {
|
||||||
// Invalid IP address
|
// Invalid IP address
|
||||||
throw InvalidConfig(
|
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.");
|
throw Exception("Failed to create socket file descriptor.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto enableReuseAddressSocketOption = 1;
|
||||||
|
|
||||||
if (::setsockopt(
|
if (::setsockopt(
|
||||||
socketFileDescriptor,
|
socketFileDescriptor,
|
||||||
SOL_SOCKET,
|
SOL_SOCKET,
|
||||||
SO_REUSEADDR,
|
SO_REUSEADDR,
|
||||||
&(this->enableReuseAddressSocketOption),
|
&(enableReuseAddressSocketOption),
|
||||||
sizeof(this->enableReuseAddressSocketOption)
|
sizeof(enableReuseAddressSocketOption)
|
||||||
) < 0
|
) < 0
|
||||||
) {
|
) {
|
||||||
Logger::error("Failed to set socket SO_REUSEADDR option.");
|
Logger::error("Failed to set socket SO_REUSEADDR option.");
|
||||||
@@ -87,13 +88,13 @@ namespace Bloom::DebugServer::Gdb
|
|||||||
) < 0
|
) < 0
|
||||||
) {
|
) {
|
||||||
throw Exception("Failed to bind address. The selected port number ("
|
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->serverSocketFileDescriptor = socketFileDescriptor;
|
||||||
|
|
||||||
this->epollInstance.addEntry(
|
this->epollInstance.addEntry(
|
||||||
this->serverSocketFileDescriptor,
|
this->serverSocketFileDescriptor.value(),
|
||||||
static_cast<std::uint16_t>(EpollEvent::READ_READY)
|
static_cast<std::uint16_t>(EpollEvent::READ_READY)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -102,8 +103,8 @@ namespace Bloom::DebugServer::Gdb
|
|||||||
static_cast<std::uint16_t>(EpollEvent::READ_READY)
|
static_cast<std::uint16_t>(EpollEvent::READ_READY)
|
||||||
);
|
);
|
||||||
|
|
||||||
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)
|
||||||
@@ -117,8 +118,8 @@ namespace Bloom::DebugServer::Gdb
|
|||||||
void GdbRspDebugServer::close() {
|
void GdbRspDebugServer::close() {
|
||||||
this->terminateActiveDebugSession();
|
this->terminateActiveDebugSession();
|
||||||
|
|
||||||
if (this->serverSocketFileDescriptor > 0) {
|
if (this->serverSocketFileDescriptor.has_value()) {
|
||||||
::close(this->serverSocketFileDescriptor);
|
::close(this->serverSocketFileDescriptor.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +192,7 @@ namespace Bloom::DebugServer::Gdb
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Connection> GdbRspDebugServer::waitForConnection() {
|
std::optional<Connection> GdbRspDebugServer::waitForConnection() {
|
||||||
if (::listen(this->serverSocketFileDescriptor, 3) != 0) {
|
if (::listen(this->serverSocketFileDescriptor.value(), 3) != 0) {
|
||||||
throw Exception("Failed to listen on server socket");
|
throw Exception("Failed to listen on server socket");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +206,10 @@ namespace Bloom::DebugServer::Gdb
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_optional<Connection>(this->serverSocketFileDescriptor, *(this->interruptEventNotifier));
|
return std::make_optional<Connection>(
|
||||||
|
this->serverSocketFileDescriptor.value(),
|
||||||
|
*(this->interruptEventNotifier)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CommandPacket> GdbRspDebugServer::waitForCommandPacket() {
|
std::unique_ptr<CommandPacket> GdbRspDebugServer::waitForCommandPacket() {
|
||||||
@@ -266,12 +270,14 @@ namespace Bloom::DebugServer::Gdb
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GdbRspDebugServer::terminateActiveDebugSession() {
|
void GdbRspDebugServer::terminateActiveDebugSession() {
|
||||||
if (this->activeDebugSession.has_value()) {
|
if (!this->activeDebugSession.has_value()) {
|
||||||
this->activeDebugSession->terminate();
|
return;
|
||||||
this->activeDebugSession = std::nullopt;
|
|
||||||
|
|
||||||
EventManager::triggerEvent(std::make_shared<Events::DebugSessionFinished>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->activeDebugSession->terminate();
|
||||||
|
this->activeDebugSession = std::nullopt;
|
||||||
|
|
||||||
|
EventManager::triggerEvent(std::make_shared<Events::DebugSessionFinished>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbRspDebugServer::onTargetControllerStateReported(const Events::TargetControllerStateReported& event) {
|
void GdbRspDebugServer::onTargetControllerStateReported(const Events::TargetControllerStateReported& event) {
|
||||||
|
|||||||
@@ -25,20 +25,16 @@
|
|||||||
#include "src/EventManager/Events/TargetControllerStateReported.hpp"
|
#include "src/EventManager/Events/TargetControllerStateReported.hpp"
|
||||||
#include "src/EventManager/Events/TargetExecutionStopped.hpp"
|
#include "src/EventManager/Events/TargetExecutionStopped.hpp"
|
||||||
|
|
||||||
#include "src/Helpers/BiMap.hpp"
|
|
||||||
|
|
||||||
namespace Bloom::DebugServer::Gdb
|
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
|
* This server employs TCP/IP sockets to interface with GDB clients. The listening address and port can be
|
||||||
* in the user's project config file.
|
* 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
|
* See https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html for more info on the GDB Remote Serial
|
||||||
* Serial Protocol.
|
* Protocol.
|
||||||
*
|
|
||||||
* @TODO: This could do with some cleaning.
|
|
||||||
*/
|
*/
|
||||||
class GdbRspDebugServer: public ServerInterface
|
class GdbRspDebugServer: public ServerInterface
|
||||||
{
|
{
|
||||||
@@ -48,6 +44,15 @@ namespace Bloom::DebugServer::Gdb
|
|||||||
EventListener& eventListener
|
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 {
|
[[nodiscard]] std::string getName() const override {
|
||||||
return "GDB Remote Serial Protocol DebugServer";
|
return "GDB Remote Serial Protocol DebugServer";
|
||||||
};
|
};
|
||||||
@@ -70,24 +75,25 @@ namespace Bloom::DebugServer::Gdb
|
|||||||
void run() override;
|
void run() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::optional<GdbDebugServerConfig> debugServerConfig;
|
/**
|
||||||
|
* User project configuration specific to the GDB RSP debug server.
|
||||||
|
*/
|
||||||
|
GdbDebugServerConfig debugServerConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DebugServerComponent's event listener.
|
||||||
|
*/
|
||||||
EventListener& eventListener;
|
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;
|
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,
|
* 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.
|
* we use an EpollInstance to monitor both this->serverSocketFileDescriptor and this->interruptEventNotifier.
|
||||||
@@ -102,9 +108,21 @@ namespace Bloom::DebugServer::Gdb
|
|||||||
EpollInstance epollInstance = EpollInstance();
|
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<int> serverSocketFileDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When a connection with a GDB client is established, a new instance of the DebugSession class is created and
|
* When a connection with a GDB client is established, a new instance of the DebugSession class is created and
|
||||||
|
|||||||
Reference in New Issue
Block a user