2021-10-02 17:39:27 +01:00
|
|
|
#include "GdbRspDebugServer.hpp"
|
|
|
|
|
|
2021-04-04 21:04:12 +01:00
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/epoll.h>
|
2021-10-06 21:12:31 +01:00
|
|
|
|
|
|
|
|
#include "src/Logger/Logger.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
#include "Exceptions/ClientDisconnected.hpp"
|
|
|
|
|
#include "Exceptions/ClientNotSupported.hpp"
|
|
|
|
|
#include "Exceptions/ClientCommunicationError.hpp"
|
2021-05-30 16:53:49 +01:00
|
|
|
#include "Exceptions/DebugSessionAborted.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
#include "src/Exceptions/Exception.hpp"
|
|
|
|
|
#include "src/Exceptions/InvalidConfig.hpp"
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
void GdbRspDebugServer::init() {
|
2022-03-19 15:16:59 +00:00
|
|
|
this->debugServerConfig = GdbDebugServerConfig(DebugServer::debugServerConfig);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->socketAddress.sin_family = AF_INET;
|
2022-03-19 15:16:59 +00:00
|
|
|
this->socketAddress.sin_port = htons(this->debugServerConfig->listeningPortNumber);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-03-19 15:16:59 +00:00
|
|
|
if (::inet_pton(
|
|
|
|
|
AF_INET,
|
|
|
|
|
this->debugServerConfig->listeningAddress.c_str(),
|
|
|
|
|
&(this->socketAddress.sin_addr)
|
|
|
|
|
) == 0
|
|
|
|
|
) {
|
2022-02-05 15:32:08 +00:00
|
|
|
// Invalid IP address
|
|
|
|
|
throw InvalidConfig(
|
2022-03-19 15:16:59 +00:00
|
|
|
"Invalid IP address provided in config file: (\"" + this->debugServerConfig->listeningAddress
|
|
|
|
|
+ "\")"
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-03-19 15:17:07 +00:00
|
|
|
int socketFileDescriptor = 0;
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if ((socketFileDescriptor = ::socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
|
|
|
|
throw Exception("Failed to create socket file descriptor.");
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (::setsockopt(
|
|
|
|
|
socketFileDescriptor,
|
|
|
|
|
SOL_SOCKET,
|
|
|
|
|
SO_REUSEADDR,
|
|
|
|
|
&(this->enableReuseAddressSocketOption),
|
|
|
|
|
sizeof(this->enableReuseAddressSocketOption)
|
|
|
|
|
) < 0
|
|
|
|
|
) {
|
|
|
|
|
Logger::error("Failed to set socket SO_REUSEADDR option.");
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (::bind(
|
|
|
|
|
socketFileDescriptor,
|
|
|
|
|
reinterpret_cast<const sockaddr*>(&(this->socketAddress)),
|
|
|
|
|
sizeof(this->socketAddress)
|
|
|
|
|
) < 0
|
|
|
|
|
) {
|
|
|
|
|
throw Exception("Failed to bind address. The selected port number ("
|
2022-03-19 15:16:59 +00:00
|
|
|
+ std::to_string(this->debugServerConfig->listeningPortNumber) + ") may be in use.");
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->serverSocketFileDescriptor = socketFileDescriptor;
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->eventFileDescriptor = ::epoll_create(2);
|
|
|
|
|
struct epoll_event event = {};
|
2021-10-06 21:12:31 +01:00
|
|
|
event.events = EPOLLIN;
|
2022-02-05 15:32:08 +00:00
|
|
|
event.data.fd = this->serverSocketFileDescriptor;
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (::epoll_ctl(this->eventFileDescriptor, EPOLL_CTL_ADD, this->serverSocketFileDescriptor, &event) != 0) {
|
|
|
|
|
throw Exception("Failed epoll_ctl server socket");
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->interruptEventNotifier != nullptr) {
|
|
|
|
|
auto interruptFileDescriptor = this->interruptEventNotifier->getFileDescriptor();
|
|
|
|
|
event.events = EPOLLIN;
|
|
|
|
|
event.data.fd = interruptFileDescriptor;
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (::epoll_ctl(this->eventFileDescriptor, EPOLL_CTL_ADD, interruptFileDescriptor, &event) != 0) {
|
|
|
|
|
throw Exception("Failed epoll_ctl interrupt event fd");
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-03-19 15:16:59 +00:00
|
|
|
Logger::info("GDB RSP address: " + this->debugServerConfig->listeningAddress);
|
|
|
|
|
Logger::info("GDB RSP port: " + std::to_string(this->debugServerConfig->listeningPortNumber));
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->eventListener->registerCallbackForEventType<Events::TargetControllerStateReported>(
|
|
|
|
|
std::bind(&GdbRspDebugServer::onTargetControllerStateReported, this, std::placeholders::_1)
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->eventListener->registerCallbackForEventType<Events::TargetExecutionStopped>(
|
|
|
|
|
std::bind(&GdbRspDebugServer::onTargetExecutionStopped, this, std::placeholders::_1)
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void GdbRspDebugServer::close() {
|
2022-03-24 19:17:41 +00:00
|
|
|
this->terminateActiveDebugSession();
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->serverSocketFileDescriptor > 0) {
|
|
|
|
|
::close(this->serverSocketFileDescriptor);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void GdbRspDebugServer::serve() {
|
|
|
|
|
try {
|
2022-03-24 19:17:41 +00:00
|
|
|
if (!this->activeDebugSession.has_value()) {
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::info("Waiting for GDB RSP connection");
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-03-24 19:17:41 +00:00
|
|
|
auto connection = this->waitForConnection();
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-03-24 19:17:41 +00:00
|
|
|
if (!connection.has_value()) {
|
|
|
|
|
// Likely an interrupt
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
connection->accept(this->serverSocketFileDescriptor);
|
|
|
|
|
Logger::info("Accepted GDP RSP connection from " + connection->getIpAddress());
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-03-25 00:17:28 +00:00
|
|
|
this->activeDebugSession.emplace(
|
|
|
|
|
DebugSession(connection.value(), this->getGdbTargetDescriptor())
|
|
|
|
|
);
|
2022-03-20 17:37:36 +00:00
|
|
|
EventManager::triggerEvent(std::make_shared<Events::DebugSessionStarted>());
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
/*
|
|
|
|
|
* Before proceeding with a new debug session, we must ensure that the TargetController is able to
|
|
|
|
|
* service it.
|
|
|
|
|
*/
|
|
|
|
|
if (!this->targetControllerConsole.isTargetControllerInService()) {
|
2022-03-24 19:17:41 +00:00
|
|
|
this->terminateActiveDebugSession();
|
2022-02-05 15:32:08 +00:00
|
|
|
throw DebugSessionAborted("TargetController not in service");
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-03-24 19:17:41 +00:00
|
|
|
// auto packets = this->activeDebugSession->connection.readPackets();
|
|
|
|
|
//
|
|
|
|
|
// // Only process the last packet - any others will likely be duplicates from an impatient client
|
|
|
|
|
// if (!packets.empty()) {
|
|
|
|
|
// // Double-dispatch to appropriate handler
|
|
|
|
|
// packets.back()->dispatchToHandler(*this);
|
|
|
|
|
// }
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} catch (const ClientDisconnected&) {
|
|
|
|
|
Logger::info("GDB RSP client disconnected");
|
2022-03-24 19:17:41 +00:00
|
|
|
this->terminateActiveDebugSession();
|
2022-02-05 15:32:08 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
} catch (const ClientCommunicationError& exception) {
|
|
|
|
|
Logger::error(
|
|
|
|
|
"GDB RSP client communication error - " + exception.getMessage() + " - closing connection"
|
|
|
|
|
);
|
2022-03-24 19:17:41 +00:00
|
|
|
this->terminateActiveDebugSession();
|
2022-02-05 15:32:08 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
} catch (const ClientNotSupported& exception) {
|
|
|
|
|
Logger::error("Invalid GDB RSP client - " + exception.getMessage() + " - closing connection");
|
2022-03-24 19:17:41 +00:00
|
|
|
this->terminateActiveDebugSession();
|
2022-02-05 15:32:08 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
} catch (const DebugSessionAborted& exception) {
|
|
|
|
|
Logger::warning("GDB debug session aborted - " + exception.getMessage());
|
2022-03-24 19:17:41 +00:00
|
|
|
this->terminateActiveDebugSession();
|
2022-02-05 15:32:08 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
} catch (const DebugServerInterrupted&) {
|
|
|
|
|
// Server was interrupted
|
|
|
|
|
Logger::debug("GDB RSP interrupted");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-03-24 19:17:41 +00:00
|
|
|
std::optional<Connection> GdbRspDebugServer::waitForConnection() {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (::listen(this->serverSocketFileDescriptor, 3) != 0) {
|
|
|
|
|
throw Exception("Failed to listen on server socket");
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
constexpr int maxEvents = 5;
|
|
|
|
|
std::array<struct epoll_event, maxEvents> events = {};
|
|
|
|
|
int eventCount = ::epoll_wait(
|
|
|
|
|
this->eventFileDescriptor,
|
|
|
|
|
events.data(),
|
|
|
|
|
maxEvents,
|
|
|
|
|
-1
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (eventCount > 0) {
|
|
|
|
|
for (size_t i = 0; i < eventCount; i++) {
|
|
|
|
|
auto fileDescriptor = events.at(i).data.fd;
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (fileDescriptor == this->interruptEventNotifier->getFileDescriptor()) {
|
|
|
|
|
// Interrupted
|
|
|
|
|
this->interruptEventNotifier->clear();
|
2022-03-24 19:17:41 +00:00
|
|
|
return std::nullopt;
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-03-24 19:17:41 +00:00
|
|
|
return Connection(this->interruptEventNotifier);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GdbRspDebugServer::terminateActiveDebugSession() {
|
|
|
|
|
if (this->activeDebugSession.has_value()) {
|
|
|
|
|
this->activeDebugSession->terminate();
|
|
|
|
|
this->activeDebugSession = std::nullopt;
|
|
|
|
|
|
|
|
|
|
EventManager::triggerEvent(std::make_shared<Events::DebugSessionFinished>());
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void GdbRspDebugServer::onTargetControllerStateReported(const Events::TargetControllerStateReported& event) {
|
2022-03-24 19:17:41 +00:00
|
|
|
if (event.state == TargetControllerState::SUSPENDED && this->activeDebugSession.has_value()) {
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::warning("Terminating debug session - TargetController suspended unexpectedly");
|
2022-03-24 19:17:41 +00:00
|
|
|
this->terminateActiveDebugSession();
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
void GdbRspDebugServer::onTargetExecutionStopped(const Events::TargetExecutionStopped&) {
|
2022-03-24 19:17:41 +00:00
|
|
|
if (this->activeDebugSession.has_value() && this->activeDebugSession->waitingForBreak) {
|
|
|
|
|
this->activeDebugSession->connection.writePacket(TargetStopped(Signal::TRAP));
|
|
|
|
|
this->activeDebugSession->waitingForBreak = false;
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
}
|