Massive refactor to accommodate RISC-V targets
- Refactored entire codebase (excluding the Insight component) to accommodate multiple target architectures (no longer specific to AVR) - Deleted 'generate SVD' GDB monitor command - I will eventually move this functionality to the Bloom website - Added unit size property to address spaces - Many other changes which I couldn't be bothered to describe here
This commit is contained in:
@@ -28,9 +28,7 @@
|
||||
#include "CommandPackets/HelpMonitorInfo.hpp"
|
||||
#include "CommandPackets/BloomVersion.hpp"
|
||||
#include "CommandPackets/BloomVersionMachine.hpp"
|
||||
#include "CommandPackets/GenerateSvd.hpp"
|
||||
#include "CommandPackets/Detach.hpp"
|
||||
#include "CommandPackets/EepromFill.hpp"
|
||||
|
||||
#ifndef EXCLUDE_INSIGHT
|
||||
#include "CommandPackets/ActivateInsight.hpp"
|
||||
@@ -51,10 +49,12 @@ namespace DebugServer::Gdb
|
||||
|
||||
GdbRspDebugServer::GdbRspDebugServer(
|
||||
const DebugServerConfig& debugServerConfig,
|
||||
const Targets::TargetDescriptor& targetDescriptor,
|
||||
EventListener& eventListener,
|
||||
EventFdNotifier& eventNotifier
|
||||
)
|
||||
: debugServerConfig(GdbDebugServerConfig(debugServerConfig))
|
||||
, targetDescriptor(targetDescriptor)
|
||||
, eventListener(eventListener)
|
||||
, interruptEventNotifier(eventNotifier)
|
||||
{}
|
||||
@@ -63,28 +63,27 @@ namespace DebugServer::Gdb
|
||||
this->socketAddress.sin_family = AF_INET;
|
||||
this->socketAddress.sin_port = htons(this->debugServerConfig.listeningPortNumber);
|
||||
|
||||
if (::inet_pton(
|
||||
if (
|
||||
::inet_pton(
|
||||
AF_INET,
|
||||
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
|
||||
+ "\")"
|
||||
);
|
||||
throw InvalidConfig{
|
||||
"Invalid IP address provided in config file: (\"" + this->debugServerConfig.listeningAddress + "\")"
|
||||
};
|
||||
}
|
||||
|
||||
int socketFileDescriptor = 0;
|
||||
|
||||
auto socketFileDescriptor = int{0};
|
||||
if ((socketFileDescriptor = ::socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
||||
throw Exception("Failed to create socket file descriptor.");
|
||||
throw Exception{"Failed to create socket file descriptor."};
|
||||
}
|
||||
|
||||
const auto enableReuseAddressSocketOption = 1;
|
||||
|
||||
if (::setsockopt(
|
||||
const auto enableReuseAddressSocketOption = int{1};
|
||||
if (
|
||||
::setsockopt(
|
||||
socketFileDescriptor,
|
||||
SOL_SOCKET,
|
||||
SO_REUSEADDR,
|
||||
@@ -95,14 +94,17 @@ namespace DebugServer::Gdb
|
||||
Logger::error("Failed to set socket SO_REUSEADDR option.");
|
||||
}
|
||||
|
||||
if (::bind(
|
||||
if (
|
||||
::bind(
|
||||
socketFileDescriptor,
|
||||
reinterpret_cast<const sockaddr*>(&(this->socketAddress)),
|
||||
sizeof(this->socketAddress)
|
||||
) < 0
|
||||
) {
|
||||
throw Exception("Failed to bind address. The selected port number ("
|
||||
+ std::to_string(this->debugServerConfig.listeningPortNumber) + ") may be in use.");
|
||||
throw Exception{
|
||||
"Failed to bind address. The selected port number ("
|
||||
+ std::to_string(this->debugServerConfig.listeningPortNumber) + ") may be in use."
|
||||
};
|
||||
}
|
||||
|
||||
this->serverSocketFileDescriptor = socketFileDescriptor;
|
||||
@@ -120,12 +122,8 @@ namespace DebugServer::Gdb
|
||||
Logger::info("GDB RSP address: " + this->debugServerConfig.listeningAddress);
|
||||
Logger::info("GDB RSP port: " + std::to_string(this->debugServerConfig.listeningPortNumber));
|
||||
|
||||
this->eventListener.registerCallbackForEventType<Events::TargetExecutionStopped>(
|
||||
std::bind(&GdbRspDebugServer::onTargetExecutionStopped, this, std::placeholders::_1)
|
||||
);
|
||||
|
||||
this->eventListener.registerCallbackForEventType<Events::TargetExecutionResumed>(
|
||||
std::bind(&GdbRspDebugServer::onTargetExecutionResumed, this, std::placeholders::_1)
|
||||
this->eventListener.registerCallbackForEventType<Events::TargetStateChanged>(
|
||||
std::bind(&GdbRspDebugServer::onTargetStateChanged, this, std::placeholders::_1)
|
||||
);
|
||||
|
||||
if (Services::ProcessService::isManagedByClion()) {
|
||||
@@ -149,7 +147,6 @@ namespace DebugServer::Gdb
|
||||
Logger::info("Waiting for GDB RSP connection");
|
||||
|
||||
auto connection = this->waitForConnection();
|
||||
|
||||
Logger::info("Accepted GDP RSP connection from " + connection.getIpAddress());
|
||||
|
||||
this->startDebugSession(std::move(connection));
|
||||
@@ -159,9 +156,13 @@ namespace DebugServer::Gdb
|
||||
}
|
||||
|
||||
const auto commandPacket = this->waitForCommandPacket();
|
||||
|
||||
if (commandPacket) {
|
||||
commandPacket->handle(*(this->getActiveDebugSession()), this->targetControllerService);
|
||||
commandPacket->handle(
|
||||
*(this->getActiveDebugSession()),
|
||||
this->getGdbTargetDescriptor(),
|
||||
this->targetDescriptor,
|
||||
this->targetControllerService
|
||||
);
|
||||
}
|
||||
|
||||
} catch (const ClientDisconnected&) {
|
||||
@@ -195,28 +196,25 @@ namespace DebugServer::Gdb
|
||||
|
||||
Connection GdbRspDebugServer::waitForConnection() {
|
||||
if (::listen(this->serverSocketFileDescriptor.value(), 3) != 0) {
|
||||
throw Exception("Failed to listen on server socket");
|
||||
throw Exception{"Failed to listen on server socket"};
|
||||
}
|
||||
|
||||
const auto eventFileDescriptor = this->epollInstance.waitForEvent();
|
||||
|
||||
if (
|
||||
!eventFileDescriptor.has_value()
|
||||
|| eventFileDescriptor.value() == this->interruptEventNotifier.getFileDescriptor()
|
||||
|| *eventFileDescriptor == this->interruptEventNotifier.getFileDescriptor()
|
||||
) {
|
||||
this->interruptEventNotifier.clear();
|
||||
throw DebugServerInterrupted();
|
||||
throw DebugServerInterrupted{};
|
||||
}
|
||||
|
||||
return Connection(
|
||||
this->serverSocketFileDescriptor.value(),
|
||||
this->interruptEventNotifier
|
||||
);
|
||||
return {this->serverSocketFileDescriptor.value(), this->interruptEventNotifier};
|
||||
}
|
||||
|
||||
std::unique_ptr<CommandPacket> GdbRspDebugServer::waitForCommandPacket() {
|
||||
auto* debugSession = this->getActiveDebugSession();
|
||||
const auto rawPackets = debugSession->connection.readRawPackets();
|
||||
assert(!rawPackets.empty());
|
||||
|
||||
if (rawPackets.size() > 1) {
|
||||
const auto& firstRawPacket = rawPackets.front();
|
||||
@@ -224,99 +222,110 @@ namespace DebugServer::Gdb
|
||||
if (firstRawPacket.size() == 5 && firstRawPacket[1] == 0x03) {
|
||||
// Interrupt packet that came in too quickly before another packet
|
||||
debugSession->pendingInterrupt = true;
|
||||
}
|
||||
|
||||
// We only process the last packet - any others will probably be duplicates from an impatient client.
|
||||
Logger::warning("Multiple packets received from GDB - only the most recent will be processed");
|
||||
} else {
|
||||
Logger::warning("Multiple packets received from GDB - only the most recent will be processed");
|
||||
}
|
||||
}
|
||||
|
||||
return this->resolveCommandPacket(rawPackets.back());
|
||||
}
|
||||
|
||||
std::unique_ptr<CommandPacket> GdbRspDebugServer::resolveCommandPacket(const RawPacket& rawPacket) {
|
||||
if (rawPacket.size() < 2) {
|
||||
throw Exception{"Invalid raw packet - no data"};
|
||||
}
|
||||
|
||||
if (rawPacket.size() == 5 && rawPacket[1] == 0x03) {
|
||||
// Interrupt request
|
||||
return std::make_unique<CommandPackets::InterruptExecution>(rawPacket);
|
||||
}
|
||||
|
||||
if (rawPacket[1] == 'c') {
|
||||
return std::make_unique<CommandPackets::ContinueExecution>(rawPacket);
|
||||
}
|
||||
|
||||
if (rawPacket[1] == 's') {
|
||||
return std::make_unique<CommandPackets::StepExecution>(rawPacket);
|
||||
}
|
||||
|
||||
if (rawPacket[1] == 'Z') {
|
||||
return std::make_unique<CommandPackets::SetBreakpoint>(rawPacket);
|
||||
}
|
||||
|
||||
if (rawPacket[1] == 'z') {
|
||||
return std::make_unique<CommandPackets::RemoveBreakpoint>(rawPacket);
|
||||
}
|
||||
|
||||
if (rawPacket[1] == 'D') {
|
||||
return std::make_unique<CommandPackets::Detach>(rawPacket);
|
||||
}
|
||||
|
||||
const auto rawPacketString = std::string(rawPacket.begin(), rawPacket.end());
|
||||
const auto rawPacketString = std::string{rawPacket.begin() + 1, rawPacket.end()};
|
||||
|
||||
if (rawPacketString.size() >= 2) {
|
||||
/*
|
||||
* First byte of the raw packet will be 0x24 ('$'), so std::string::find() should return 1, not 0, when
|
||||
* looking for a command identifier string.
|
||||
*/
|
||||
if (rawPacketString.find("qSupported") == 1) {
|
||||
return std::make_unique<CommandPackets::SupportedFeaturesQuery>(rawPacket);
|
||||
/*
|
||||
* First byte of the raw packet will be 0x24 ('$'), so std::string::find() should return 1, not 0, when
|
||||
* looking for a command identifier string.
|
||||
*/
|
||||
if (rawPacketString.find("qSupported") == 0) {
|
||||
return std::make_unique<CommandPackets::SupportedFeaturesQuery>(rawPacket);
|
||||
}
|
||||
|
||||
if (rawPacketString.find("qRcmd") == 0) {
|
||||
// This is a monitor packet
|
||||
auto monitorCommand = std::make_unique<CommandPackets::Monitor>(rawPacket);
|
||||
|
||||
if (monitorCommand->command == "help") {
|
||||
return std::make_unique<CommandPackets::HelpMonitorInfo>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
|
||||
if (rawPacketString[1] == 'c') {
|
||||
return std::make_unique<CommandPackets::ContinueExecution>(rawPacket);
|
||||
if (monitorCommand->command == "version") {
|
||||
return std::make_unique<CommandPackets::BloomVersion>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
|
||||
if (rawPacketString[1] == 's') {
|
||||
return std::make_unique<CommandPackets::StepExecution>(rawPacket);
|
||||
if (monitorCommand->command == "version machine") {
|
||||
return std::make_unique<CommandPackets::BloomVersionMachine>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
|
||||
if (rawPacketString[1] == 'Z') {
|
||||
return std::make_unique<CommandPackets::SetBreakpoint>(rawPacket);
|
||||
if (monitorCommand->command == "reset") {
|
||||
return std::make_unique<CommandPackets::ResetTarget>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
|
||||
if (rawPacketString[1] == 'z') {
|
||||
return std::make_unique<CommandPackets::RemoveBreakpoint>(rawPacket);
|
||||
}
|
||||
|
||||
if (rawPacketString.find("qRcmd") == 1) {
|
||||
// This is a monitor packet
|
||||
auto monitorCommand = std::make_unique<CommandPackets::Monitor>(rawPacket);
|
||||
|
||||
if (monitorCommand->command == "help") {
|
||||
return std::make_unique<CommandPackets::HelpMonitorInfo>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
|
||||
if (monitorCommand->command == "version") {
|
||||
return std::make_unique<CommandPackets::BloomVersion>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
|
||||
if (monitorCommand->command == "version machine") {
|
||||
return std::make_unique<CommandPackets::BloomVersionMachine>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
|
||||
if (monitorCommand->command == "reset") {
|
||||
return std::make_unique<CommandPackets::ResetTarget>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
|
||||
if (monitorCommand->command.find("svd") == 0) {
|
||||
return std::make_unique<CommandPackets::GenerateSvd>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
|
||||
if (monitorCommand->command.find("eeprom fill") == 0) {
|
||||
return std::make_unique<CommandPackets::EepromFill>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
#ifndef EXCLUDE_INSIGHT
|
||||
if (monitorCommand->command.find("insight") == 0) {
|
||||
return std::make_unique<CommandPackets::ActivateInsight>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
#endif
|
||||
return monitorCommand;
|
||||
if (monitorCommand->command.find("insight") == 0) {
|
||||
return std::make_unique<CommandPackets::ActivateInsight>(std::move(*(monitorCommand.release())));
|
||||
}
|
||||
#endif
|
||||
return monitorCommand;
|
||||
}
|
||||
|
||||
return std::make_unique<CommandPacket>(rawPacket);
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::onTargetExecutionStopped(const Events::TargetExecutionStopped& stoppedEvent) {
|
||||
using Services::StringService;
|
||||
void GdbRspDebugServer::onTargetStateChanged(const Events::TargetStateChanged& event) {
|
||||
using Targets::TargetExecutionState;
|
||||
|
||||
auto* debugSession = this->getActiveDebugSession();
|
||||
if (debugSession == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.newState.executionState == event.previousState.executionState) {
|
||||
// Execution state hasn't changed. Probably just a mode change. Ignore...
|
||||
return;
|
||||
}
|
||||
|
||||
const auto executionState = event.newState.executionState.load();
|
||||
|
||||
try {
|
||||
if (debugSession != nullptr && debugSession->waitingForBreak) {
|
||||
this->handleTargetStoppedGdbResponse(stoppedEvent.programCounter);
|
||||
if (executionState == TargetExecutionState::STOPPED && debugSession->waitingForBreak) {
|
||||
this->handleTargetStoppedGdbResponse(event.newState.programCounter.load().value());
|
||||
return;
|
||||
}
|
||||
|
||||
if (executionState == TargetExecutionState::RUNNING || executionState == TargetExecutionState::STEPPING) {
|
||||
this->handleTargetResumedGdbResponse();
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (const ClientDisconnected&) {
|
||||
@@ -335,41 +344,12 @@ namespace DebugServer::Gdb
|
||||
// Server was interrupted
|
||||
Logger::debug("GDB RSP interrupted");
|
||||
return;
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to handle target execution stopped event - " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::onTargetExecutionResumed(const Events::TargetExecutionResumed&) {
|
||||
auto* debugSession = this->getActiveDebugSession();
|
||||
|
||||
try {
|
||||
if (debugSession != nullptr) {
|
||||
this->handleTargetResumedGdbResponse();
|
||||
}
|
||||
|
||||
} catch (const ClientDisconnected&) {
|
||||
Logger::info("GDB RSP client disconnected");
|
||||
this->endDebugSession();
|
||||
return;
|
||||
|
||||
} catch (const ClientCommunicationError& exception) {
|
||||
Logger::error(
|
||||
"GDB RSP client communication error - " + exception.getMessage() + " - closing connection"
|
||||
);
|
||||
this->endDebugSession();
|
||||
return;
|
||||
|
||||
} catch (const DebugServerInterrupted&) {
|
||||
// Server was interrupted
|
||||
Logger::debug("GDB RSP interrupted");
|
||||
return;
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to handle target execution resumed event - " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::handleTargetStoppedGdbResponse(Targets::TargetMemoryAddress programAddress) {
|
||||
auto* debugSession = this->getActiveDebugSession();
|
||||
|
||||
@@ -377,7 +357,7 @@ namespace DebugServer::Gdb
|
||||
debugSession->terminateRangeSteppingSession(this->targetControllerService);
|
||||
}
|
||||
|
||||
debugSession->connection.writePacket(ResponsePackets::TargetStopped(Signal::TRAP));
|
||||
debugSession->connection.writePacket(ResponsePackets::TargetStopped{Signal::TRAP});
|
||||
debugSession->waitingForBreak = false;
|
||||
}
|
||||
|
||||
@@ -392,7 +372,7 @@ namespace DebugServer::Gdb
|
||||
debugSession->terminateRangeSteppingSession(this->targetControllerService);
|
||||
}
|
||||
|
||||
debugSession->connection.writePacket(ResponsePackets::TargetStopped(Signal::INTERRUPTED));
|
||||
debugSession->connection.writePacket(ResponsePackets::TargetStopped{Signal::INTERRUPTED});
|
||||
debugSession->pendingInterrupt = false;
|
||||
debugSession->waitingForBreak = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user