Moved GDB command packet handling to individual CommandPacket classes
This commit is contained in:
@@ -129,16 +129,14 @@ add_executable(Bloom
|
||||
src/DebugServers/GdbRsp/GdbDebugServerConfig.cpp
|
||||
src/DebugServers/GdbRsp/Connection.cpp
|
||||
src/DebugServers/GdbRsp/DebugSession.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/CommandPacket.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/CommandPacketFactory.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/CommandPacket.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/SupportedFeaturesQuery.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/ReadRegisters.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/WriteRegister.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/ContinueExecution.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/StepExecution.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/InterruptExecution.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/ReadMemory.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/WriteMemory.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/SetBreakpoint.cpp
|
||||
src/DebugServers/GdbRsp/CommandPackets/RemoveBreakpoint.cpp
|
||||
src/DebugServers/GdbRsp/ResponsePackets/SupportedFeaturesResponse.cpp
|
||||
@@ -146,6 +144,10 @@ add_executable(Bloom
|
||||
# AVR GDB Server
|
||||
src/DebugServers/GdbRsp/AvrGdb/AvrGdbRsp.cpp
|
||||
src/DebugServers/GdbRsp/AvrGdb/TargetDescriptor.cpp
|
||||
src/DebugServers/GdbRsp/AvrGdb/CommandPackets/AbstractMemoryAccessPacket.cpp
|
||||
src/DebugServers/GdbRsp/AvrGdb/CommandPackets/ReadMemory.cpp
|
||||
src/DebugServers/GdbRsp/AvrGdb/CommandPackets/WriteMemory.cpp
|
||||
|
||||
# Insight
|
||||
src/Insight/Insight.cpp
|
||||
src/Insight/InsightWorker/InsightWorker.cpp
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "AbstractMemoryAccessPacket.hpp"
|
||||
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/TargetStopped.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
#include "src/DebugServers/GdbRsp/Signal.hpp"
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
|
||||
using Exceptions::Exception;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#include "src/DebugServers/GdbRsp/CommandPackets/CommandPacket.hpp"
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::AvrGdb::CommandPackets
|
||||
{
|
||||
/**
|
||||
* The ReadMemory class implements a structure for "m" packets. Upon receiving these packets, the server is
|
||||
* expected to read memory from the target and send it the client.
|
||||
*/
|
||||
class AbstractMemoryAccessPacket: public Bloom::DebugServers::Gdb::CommandPackets::CommandPacket
|
||||
{
|
||||
public:
|
||||
explicit AbstractMemoryAccessPacket(const std::vector<unsigned char>& rawPacket): CommandPacket(rawPacket) {};
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The mask used by the AVR GDB client to encode the memory type into memory addresses.
|
||||
*/
|
||||
static constexpr std::uint32_t AVR_GDB_MEMORY_ADDRESS_MASK = 0xFE0000U;
|
||||
|
||||
/**
|
||||
* avr-gdb uses the most significant 15 bits in memory addresses to indicate the type of memory being
|
||||
* addressed.
|
||||
*
|
||||
* @param address
|
||||
* @return
|
||||
*/
|
||||
Targets::TargetMemoryType getMemoryTypeFromGdbAddress(std::uint32_t address) {
|
||||
if ((address & AbstractMemoryAccessPacket::AVR_GDB_MEMORY_ADDRESS_MASK) != 0U) {
|
||||
return Targets::TargetMemoryType::RAM;
|
||||
}
|
||||
|
||||
return Targets::TargetMemoryType::FLASH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips the most significant 15 bits from a GDB memory address.
|
||||
*
|
||||
* @param address
|
||||
* @return
|
||||
*/
|
||||
std::uint32_t removeMemoryTypeIndicatorFromGdbAddress(std::uint32_t address) {
|
||||
return (address & AbstractMemoryAccessPacket::AVR_GDB_MEMORY_ADDRESS_MASK) != 0U
|
||||
? (address & ~(AbstractMemoryAccessPacket::AVR_GDB_MEMORY_ADDRESS_MASK))
|
||||
: address;
|
||||
}
|
||||
};
|
||||
}
|
||||
70
src/DebugServers/GdbRsp/AvrGdb/CommandPackets/ReadMemory.cpp
Normal file
70
src/DebugServers/GdbRsp/AvrGdb/CommandPackets/ReadMemory.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include "ReadMemory.hpp"
|
||||
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ResponsePacket.hpp"
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::AvrGdb::CommandPackets
|
||||
{
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
using ResponsePackets::ResponsePacket;
|
||||
|
||||
using Exceptions::Exception;
|
||||
|
||||
void ReadMemory::init() {
|
||||
if (this->data.size() < 4) {
|
||||
throw Exception("Invalid packet length");
|
||||
}
|
||||
|
||||
auto packetString = QString::fromLocal8Bit(
|
||||
reinterpret_cast<const char*>(this->data.data() + 1),
|
||||
static_cast<int>(this->data.size() - 1)
|
||||
);
|
||||
|
||||
/*
|
||||
* The read memory ('m') packet consists of two segments, an address and a number of bytes to read.
|
||||
* These are separated by a comma character.
|
||||
*/
|
||||
auto packetSegments = packetString.split(",");
|
||||
|
||||
if (packetSegments.size() != 2) {
|
||||
throw Exception(
|
||||
"Unexpected number of segments in packet data: " + std::to_string(packetSegments.size())
|
||||
);
|
||||
}
|
||||
|
||||
bool conversionStatus = false;
|
||||
this->startAddress = packetSegments.at(0).toUInt(&conversionStatus, 16);
|
||||
|
||||
if (!conversionStatus) {
|
||||
throw Exception("Failed to parse start address from read memory packet data");
|
||||
}
|
||||
|
||||
this->bytes = packetSegments.at(1).toUInt(&conversionStatus, 16);
|
||||
|
||||
if (!conversionStatus) {
|
||||
throw Exception("Failed to parse read length from read memory packet data");
|
||||
}
|
||||
}
|
||||
|
||||
void ReadMemory::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {
|
||||
Logger::debug("Handling ReadMemory packet");
|
||||
|
||||
try {
|
||||
auto memoryType = this->getMemoryTypeFromGdbAddress(this->startAddress);
|
||||
auto startAddress = this->removeMemoryTypeIndicatorFromGdbAddress(this->startAddress);
|
||||
auto memoryBuffer = targetControllerConsole.readMemory(memoryType, startAddress, this->bytes);
|
||||
|
||||
auto hexMemoryBuffer = Packet::dataToHex(memoryBuffer);
|
||||
debugSession.connection.writePacket(
|
||||
ResponsePacket(std::vector<unsigned char>(hexMemoryBuffer.begin(), hexMemoryBuffer.end()))
|
||||
);
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to read memory from target - " + exception.getMessage());
|
||||
debugSession.connection.writePacket(ErrorResponsePacket());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,15 @@
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#include "CommandPacket.hpp"
|
||||
#include "AbstractMemoryAccessPacket.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
namespace Bloom::DebugServers::Gdb::AvrGdb::CommandPackets
|
||||
{
|
||||
/**
|
||||
* The ReadMemory class implements a structure for "m" packets. Upon receiving these packets, the server is
|
||||
* expected to read memory from the target and send it the client.
|
||||
*/
|
||||
class ReadMemory: public CommandPacket
|
||||
class ReadMemory: public AbstractMemoryAccessPacket
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -28,13 +28,13 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
*/
|
||||
std::uint32_t bytes = 0;
|
||||
|
||||
explicit ReadMemory(const std::vector<unsigned char>& rawPacket): CommandPacket(rawPacket) {
|
||||
explicit ReadMemory(const std::vector<unsigned char>& rawPacket): AbstractMemoryAccessPacket(rawPacket) {
|
||||
init();
|
||||
};
|
||||
|
||||
void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override;
|
||||
void handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) override;
|
||||
|
||||
private:
|
||||
protected:
|
||||
void init();
|
||||
};
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
#include "WriteMemory.hpp"
|
||||
|
||||
#include "src/DebugServers/GdbRsp/GdbRspDebugServer.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/OkResponsePacket.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::AvrGdb::CommandPackets
|
||||
{
|
||||
using namespace Bloom::Exceptions;
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
using ResponsePackets::OkResponsePacket;
|
||||
|
||||
void WriteMemory::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) {
|
||||
gdbRspDebugServer.handleGdbPacket(*this);
|
||||
}
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
void WriteMemory::init() {
|
||||
if (this->data.size() < 4) {
|
||||
@@ -57,4 +60,27 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
throw Exception("Buffer size does not match length value given in write memory packet");
|
||||
}
|
||||
}
|
||||
|
||||
void WriteMemory::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {
|
||||
Logger::debug("Handling WriteMemory packet");
|
||||
|
||||
try {
|
||||
const auto memoryType = this->getMemoryTypeFromGdbAddress(this->startAddress);
|
||||
|
||||
if (memoryType == Targets::TargetMemoryType::FLASH) {
|
||||
throw Exception(
|
||||
"GDB client requested a flash memory write - This is not currently supported by Bloom."
|
||||
);
|
||||
}
|
||||
|
||||
const auto startAddress = this->removeMemoryTypeIndicatorFromGdbAddress(this->startAddress);
|
||||
targetControllerConsole.writeMemory(memoryType, startAddress, this->buffer);
|
||||
|
||||
debugSession.connection.writePacket(OkResponsePacket());
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to write memory to target - " + exception.getMessage());
|
||||
debugSession.connection.writePacket(ErrorResponsePacket());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,16 +3,15 @@
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#include "CommandPacket.hpp"
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
#include "AbstractMemoryAccessPacket.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
namespace Bloom::DebugServers::Gdb::AvrGdb::CommandPackets
|
||||
{
|
||||
/**
|
||||
* The WriteMemory class implements the structure for "M" packets. Upon receiving this packet, the server is
|
||||
* expected to write data to the target's memory, at the specified start address.
|
||||
*/
|
||||
class WriteMemory: public CommandPacket
|
||||
class WriteMemory: public AbstractMemoryAccessPacket
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -23,11 +22,11 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
|
||||
Targets::TargetMemoryBuffer buffer;
|
||||
|
||||
explicit WriteMemory(const std::vector<unsigned char>& rawPacket): CommandPacket(rawPacket) {
|
||||
explicit WriteMemory(const std::vector<unsigned char>& rawPacket): AbstractMemoryAccessPacket(rawPacket) {
|
||||
init();
|
||||
};
|
||||
|
||||
void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override;
|
||||
void handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) override;
|
||||
|
||||
private:
|
||||
void init();
|
||||
@@ -1,10 +1,45 @@
|
||||
#include "CommandPacket.hpp"
|
||||
|
||||
#include "src/DebugServers/GdbRsp/GdbRspDebugServer.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ResponsePacket.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/OkResponsePacket.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/TargetStopped.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
|
||||
#include "src/DebugServers/GdbRsp/Signal.hpp"
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
void CommandPacket::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) {
|
||||
gdbRspDebugServer.handleGdbPacket(*this);
|
||||
using ResponsePackets::ResponsePacket;
|
||||
using ResponsePackets::OkResponsePacket;
|
||||
using ResponsePackets::TargetStopped;
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
|
||||
using Exceptions::Exception;
|
||||
|
||||
void CommandPacket::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {
|
||||
auto packetData = this->getData();
|
||||
auto packetString = std::string(packetData.begin(), packetData.end());
|
||||
|
||||
if (packetString[0] == '?') {
|
||||
// Status report
|
||||
debugSession.connection.writePacket(TargetStopped(Signal::TRAP));
|
||||
|
||||
} else if (packetString[0] == 'D') {
|
||||
// Detach packet - there's not really anything we need to do here, so just respond with an OK
|
||||
debugSession.connection.writePacket(OkResponsePacket());
|
||||
|
||||
} else if (packetString.find("qAttached") == 0) {
|
||||
Logger::debug("Handling qAttached");
|
||||
debugSession.connection.writePacket(ResponsePacket({1}));
|
||||
|
||||
} else {
|
||||
Logger::debug("Unknown GDB RSP packet: " + packetString + " - returning empty response");
|
||||
|
||||
// Respond with an empty packet
|
||||
debugSession.connection.writePacket(ResponsePacket({0}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
#include <memory>
|
||||
|
||||
#include "src/DebugServers/GdbRsp/Packet.hpp"
|
||||
#include "src/DebugServers/GdbRsp/DebugSession.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb {
|
||||
class GdbRspDebugServer;
|
||||
}
|
||||
#include "src/TargetController/TargetControllerConsole.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
@@ -40,12 +39,13 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
explicit CommandPacket(const std::vector<unsigned char>& rawPacket): Packet(rawPacket) {}
|
||||
|
||||
/**
|
||||
* Double dispatches the packet to the appropriate overload of handleGdbPacket(), within the passed instance of
|
||||
* GdbRspDebugServer. If there is no overload defined for a specific CommandPacket-inherited type, the
|
||||
* generic GdbRspDebugServer::handleGdbPacket(CommandPacket&) is used.
|
||||
* Should handle the command for the current active debug session.
|
||||
*
|
||||
* @param gdbRspDebugServer
|
||||
* @param debugSession
|
||||
* The current active debug session.
|
||||
*
|
||||
* @param targetControllerConsole
|
||||
*/
|
||||
virtual void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer);
|
||||
virtual void handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -119,13 +119,13 @@ namespace Bloom::DebugServers::Gdb
|
||||
return std::make_unique<CommandPackets::StepExecution>(rawPacket);
|
||||
}
|
||||
|
||||
if (rawPacketString[1] == 'm') {
|
||||
return std::make_unique<CommandPackets::ReadMemory>(rawPacket);
|
||||
}
|
||||
|
||||
if (rawPacketString[1] == 'M') {
|
||||
return std::make_unique<CommandPackets::WriteMemory>(rawPacket);
|
||||
}
|
||||
// if (rawPacketString[1] == 'm') {
|
||||
// return std::make_unique<CommandPackets::ReadMemory>(rawPacket);
|
||||
// }
|
||||
//
|
||||
// if (rawPacketString[1] == 'M') {
|
||||
// return std::make_unique<CommandPackets::WriteMemory>(rawPacket);
|
||||
// }
|
||||
|
||||
if (rawPacketString[1] == 'Z') {
|
||||
return std::make_unique<CommandPackets::SetBreakpoint>(rawPacket);
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#include "SupportedFeaturesQuery.hpp"
|
||||
#include "ReadRegisters.hpp"
|
||||
#include "WriteRegister.hpp"
|
||||
#include "ReadMemory.hpp"
|
||||
#include "WriteMemory.hpp"
|
||||
#include "StepExecution.hpp"
|
||||
#include "ContinueExecution.hpp"
|
||||
#include "SetBreakpoint.hpp"
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "ContinueExecution.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
|
||||
#include "src/DebugServers/GdbRsp/GdbRspDebugServer.hpp"
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
void ContinueExecution::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) {
|
||||
gdbRspDebugServer.handleGdbPacket(*this);
|
||||
}
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
using Exceptions::Exception;
|
||||
|
||||
void ContinueExecution::init() {
|
||||
if (this->data.size() > 1) {
|
||||
@@ -17,4 +17,17 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void ContinueExecution::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {
|
||||
Logger::debug("Handling ContinueExecution packet");
|
||||
|
||||
try {
|
||||
targetControllerConsole.continueTargetExecution(this->fromProgramCounter);
|
||||
debugSession.waitingForBreak = true;
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to continue execution on target - " + exception.getMessage());
|
||||
debugSession.connection.writePacket(ErrorResponsePacket());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
init();
|
||||
}
|
||||
|
||||
void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override;
|
||||
void handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) override;
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
#include "InterruptExecution.hpp"
|
||||
|
||||
#include "src/DebugServers/GdbRsp/GdbRspDebugServer.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/TargetStopped.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
#include "src/DebugServers/GdbRsp/Signal.hpp"
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
void InterruptExecution::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) {
|
||||
gdbRspDebugServer.handleGdbPacket(*this);
|
||||
using ResponsePackets::TargetStopped;
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
using Exceptions::Exception;
|
||||
|
||||
void InterruptExecution::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {
|
||||
Logger::debug("Handling InterruptExecution packet");
|
||||
|
||||
try {
|
||||
targetControllerConsole.stopTargetExecution();
|
||||
debugSession.connection.writePacket(TargetStopped(Signal::INTERRUPTED));
|
||||
debugSession.waitingForBreak = false;
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to interrupt execution - " + exception.getMessage());
|
||||
debugSession.connection.writePacket(ErrorResponsePacket());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,6 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
public:
|
||||
explicit InterruptExecution(const std::vector<unsigned char>& rawPacket): CommandPacket(rawPacket) {}
|
||||
|
||||
void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override;
|
||||
void handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) override;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#include "ReadMemory.hpp"
|
||||
|
||||
#include "src/DebugServers/GdbRsp/GdbRspDebugServer.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
void ReadMemory::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) {
|
||||
gdbRspDebugServer.handleGdbPacket(*this);
|
||||
}
|
||||
|
||||
void ReadMemory::init() {
|
||||
if (this->data.size() < 4) {
|
||||
throw Exception("Invalid packet length");
|
||||
}
|
||||
|
||||
auto packetString = QString::fromLocal8Bit(
|
||||
reinterpret_cast<const char*>(this->data.data() + 1),
|
||||
static_cast<int>(this->data.size() - 1)
|
||||
);
|
||||
|
||||
/*
|
||||
* The read memory ('m') packet consists of two segments, an address and a number of bytes to read.
|
||||
* These are separated by a comma character.
|
||||
*/
|
||||
auto packetSegments = packetString.split(",");
|
||||
|
||||
if (packetSegments.size() != 2) {
|
||||
throw Exception(
|
||||
"Unexpected number of segments in packet data: " + std::to_string(packetSegments.size())
|
||||
);
|
||||
}
|
||||
|
||||
bool conversionStatus = false;
|
||||
this->startAddress = packetSegments.at(0).toUInt(&conversionStatus, 16);
|
||||
|
||||
if (!conversionStatus) {
|
||||
throw Exception("Failed to parse start address from read memory packet data");
|
||||
}
|
||||
|
||||
this->bytes = packetSegments.at(1).toUInt(&conversionStatus, 16);
|
||||
|
||||
if (!conversionStatus) {
|
||||
throw Exception("Failed to parse read length from read memory packet data");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,22 @@
|
||||
#include "ReadRegisters.hpp"
|
||||
|
||||
#include "src/DebugServers/GdbRsp/GdbRspDebugServer.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/TargetStopped.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
|
||||
#include "src/Targets/TargetRegister.hpp"
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
void ReadRegisters::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) {
|
||||
gdbRspDebugServer.handleGdbPacket(*this);
|
||||
}
|
||||
using Targets::TargetRegister;
|
||||
using Targets::TargetRegisterDescriptors;
|
||||
|
||||
using ResponsePackets::ResponsePacket;
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
|
||||
using Exceptions::Exception;
|
||||
|
||||
void ReadRegisters::init() {
|
||||
if (this->data.size() >= 2 && this->data.front() == 'p') {
|
||||
@@ -16,4 +26,69 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void ReadRegisters::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {
|
||||
Logger::debug("Handling ReadRegisters packet");
|
||||
|
||||
try {
|
||||
const auto& targetDescriptor = debugSession.targetDescriptor;
|
||||
auto descriptors = TargetRegisterDescriptors();
|
||||
|
||||
if (this->registerNumber.has_value()) {
|
||||
Logger::debug("Reading register number: " + std::to_string(this->registerNumber.value()));
|
||||
descriptors.insert(targetDescriptor.getTargetRegisterDescriptorFromNumber(this->registerNumber.value()));
|
||||
|
||||
} else {
|
||||
// Read all target registers mapped to a GDB register
|
||||
for (const auto& descriptor : targetDescriptor.getRegisterNumberToDescriptorMapping().getMap()) {
|
||||
descriptors.insert(targetDescriptor.getTargetRegisterDescriptorFromNumber(descriptor.second.number));
|
||||
}
|
||||
}
|
||||
|
||||
auto registerSet = targetControllerConsole.readRegisters(descriptors);
|
||||
|
||||
/*
|
||||
* Sort each register by their respective GDB register number - this will leave us with a collection of
|
||||
* registers in the order expected by the GDB client.
|
||||
*/
|
||||
std::sort(
|
||||
registerSet.begin(),
|
||||
registerSet.end(),
|
||||
[this](const TargetRegister& registerA, const TargetRegister& registerB) {
|
||||
return targetDescriptor.getRegisterNumberFromTargetRegisterDescriptor(registerA.descriptor) <
|
||||
targetDescriptor.getRegisterNumberFromTargetRegisterDescriptor(registerB.descriptor);
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
* Finally, reverse the register values (as they're all currently in MSB, but GDB expects them in LSB), ensure
|
||||
* that each register value size matches the size in the associated GDB register descriptor, implode the
|
||||
* values, convert to hexadecimal form and send to the GDB client.
|
||||
*/
|
||||
auto registers = std::vector<unsigned char>();
|
||||
for (auto& reg : registerSet) {
|
||||
std::reverse(reg.value.begin(), reg.value.end());
|
||||
|
||||
const auto gdbRegisterNumber = targetDescriptor.getRegisterNumberFromTargetRegisterDescriptor(
|
||||
reg.descriptor
|
||||
).value();
|
||||
const auto& gdbRegisterDescriptor = targetDescriptor.getRegisterDescriptorFromNumber(gdbRegisterNumber);
|
||||
|
||||
if (reg.value.size() < gdbRegisterDescriptor.size) {
|
||||
reg.value.insert(reg.value.end(), (gdbRegisterDescriptor.size - reg.value.size()), 0x00);
|
||||
}
|
||||
|
||||
registers.insert(registers.end(), reg.value.begin(), reg.value.end());
|
||||
}
|
||||
|
||||
auto responseRegisters = Packet::dataToHex(registers);
|
||||
debugSession.connection.writePacket(
|
||||
ResponsePacket(std::vector<unsigned char>(responseRegisters.begin(), responseRegisters.end()))
|
||||
);
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to read general registers - " + exception.getMessage());
|
||||
debugSession.connection.writePacket(ErrorResponsePacket());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
init();
|
||||
};
|
||||
|
||||
void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override;
|
||||
void handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) override;
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
@@ -2,15 +2,22 @@
|
||||
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include "src/DebugServers/GdbRsp/GdbRspDebugServer.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/OkResponsePacket.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
|
||||
#include "src/Targets/TargetBreakpoint.hpp"
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
using namespace Bloom::Exceptions;
|
||||
using Targets::TargetBreakpoint;
|
||||
|
||||
void RemoveBreakpoint::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) {
|
||||
gdbRspDebugServer.handleGdbPacket(*this);
|
||||
}
|
||||
using ResponsePackets::OkResponsePacket;
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
|
||||
using Exceptions::Exception;
|
||||
|
||||
void RemoveBreakpoint::init() {
|
||||
if (data.size() < 6) {
|
||||
@@ -38,4 +45,20 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
throw Exception("Failed to convert address hex value from RemoveBreakpoint packet.");
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveBreakpoint::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {
|
||||
Logger::debug("Removing breakpoint at address " + std::to_string(this->address));
|
||||
|
||||
try {
|
||||
auto breakpoint = TargetBreakpoint();
|
||||
breakpoint.address = this->address;
|
||||
targetControllerConsole.removeBreakpoint(breakpoint);
|
||||
|
||||
debugSession.connection.writePacket(OkResponsePacket());
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to remove breakpoint on target - " + exception.getMessage());
|
||||
debugSession.connection.writePacket(ErrorResponsePacket());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,8 @@
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#include "../BreakpointType.hpp"
|
||||
#include "CommandPacket.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb
|
||||
{
|
||||
enum class Feature: int;
|
||||
}
|
||||
#include "src/DebugServers/GdbRsp/BreakpointType.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
@@ -35,7 +30,7 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
this->init();
|
||||
};
|
||||
|
||||
void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override;
|
||||
void handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) override;
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
@@ -2,15 +2,22 @@
|
||||
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include "src/DebugServers/GdbRsp/GdbRspDebugServer.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/OkResponsePacket.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
|
||||
#include "src/Targets/TargetBreakpoint.hpp"
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
using namespace Bloom::Exceptions;
|
||||
using Targets::TargetBreakpoint;
|
||||
|
||||
void SetBreakpoint::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) {
|
||||
gdbRspDebugServer.handleGdbPacket(*this);
|
||||
}
|
||||
using ResponsePackets::OkResponsePacket;
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
|
||||
using Exceptions::Exception;
|
||||
|
||||
void SetBreakpoint::init() {
|
||||
if (data.size() < 6) {
|
||||
@@ -38,4 +45,20 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
throw Exception("Failed to convert address hex value from SetBreakpoint packet.");
|
||||
}
|
||||
}
|
||||
|
||||
void SetBreakpoint::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {
|
||||
Logger::debug("Handling SetBreakpoint packet");
|
||||
|
||||
try {
|
||||
auto breakpoint = TargetBreakpoint();
|
||||
breakpoint.address = this->address;
|
||||
targetControllerConsole.setBreakpoint(breakpoint);
|
||||
|
||||
debugSession.connection.writePacket(OkResponsePacket());
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to set breakpoint on target - " + exception.getMessage());
|
||||
debugSession.connection.writePacket(ErrorResponsePacket());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,8 @@
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#include "../BreakpointType.hpp"
|
||||
#include "CommandPacket.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb
|
||||
{
|
||||
enum class Feature: int;
|
||||
}
|
||||
#include "src/DebugServers/GdbRsp/BreakpointType.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
@@ -35,7 +30,7 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
this->init();
|
||||
};
|
||||
|
||||
void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override;
|
||||
void handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) override;
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#include "StepExecution.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
|
||||
#include "src/DebugServers/GdbRsp/GdbRspDebugServer.hpp"
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
void StepExecution::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) {
|
||||
gdbRspDebugServer.handleGdbPacket(*this);
|
||||
}
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
|
||||
using Exceptions::Exception;
|
||||
|
||||
void StepExecution::init() {
|
||||
if (this->data.size() > 1) {
|
||||
@@ -17,4 +18,17 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void StepExecution::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {
|
||||
Logger::debug("Handling StepExecution packet");
|
||||
|
||||
try {
|
||||
targetControllerConsole.stepTargetExecution(this->fromProgramCounter);
|
||||
debugSession.waitingForBreak = true;
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to step execution on target - " + exception.getMessage());
|
||||
debugSession.connection.writePacket(ErrorResponsePacket());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#include "CommandPacket.hpp"
|
||||
@@ -22,7 +23,7 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
init();
|
||||
};
|
||||
|
||||
void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override;
|
||||
void handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) override;
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
@@ -2,13 +2,22 @@
|
||||
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include "src/DebugServers/GdbRsp/GdbRspDebugServer.hpp"
|
||||
#include "src/DebugServers/GdbRsp/Feature.hpp"
|
||||
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/SupportedFeaturesResponse.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
#include "src/DebugServers/GdbRsp/Exceptions/ClientNotSupported.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
void SupportedFeaturesQuery::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) {
|
||||
gdbRspDebugServer.handleGdbPacket(*this);
|
||||
}
|
||||
using ResponsePackets::SupportedFeaturesResponse;
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
|
||||
using Bloom::Exceptions::Exception;
|
||||
using Gdb::Exceptions::ClientNotSupported;
|
||||
|
||||
void SupportedFeaturesQuery::init() {
|
||||
/*
|
||||
@@ -41,4 +50,23 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SupportedFeaturesQuery::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {
|
||||
Logger::debug("Handling QuerySupport packet");
|
||||
|
||||
if (!this->isFeatureSupported(Feature::HARDWARE_BREAKPOINTS)
|
||||
&& !this->isFeatureSupported(Feature::SOFTWARE_BREAKPOINTS)
|
||||
) {
|
||||
// All GDB clients are expected to support breakpoints!
|
||||
throw ClientNotSupported("GDB client does not support HW or SW breakpoints");
|
||||
}
|
||||
|
||||
// Respond with a SupportedFeaturesResponse packet, listing all supported GDB features by Bloom
|
||||
auto response = SupportedFeaturesResponse({
|
||||
{Feature::SOFTWARE_BREAKPOINTS, std::nullopt},
|
||||
{Feature::PACKET_SIZE, std::to_string(debugSession.connection.getMaxPacketSize())},
|
||||
});
|
||||
|
||||
debugSession.connection.writePacket(response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
return this->supportedFeatures;
|
||||
}
|
||||
|
||||
void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override;
|
||||
void handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) override;
|
||||
|
||||
private:
|
||||
std::set<Feature> supportedFeatures;
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
#include "WriteRegister.hpp"
|
||||
|
||||
#include "src/DebugServers/GdbRsp/GdbRspDebugServer.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/TargetStopped.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/OkResponsePacket.hpp"
|
||||
#include "src/DebugServers/GdbRsp/ResponsePackets/ErrorResponsePacket.hpp"
|
||||
|
||||
#include "src/Targets/TargetRegister.hpp"
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
{
|
||||
using namespace Bloom::Exceptions;
|
||||
using Targets::TargetRegister;
|
||||
using Targets::TargetRegisterDescriptors;
|
||||
|
||||
void WriteRegister::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) {
|
||||
gdbRspDebugServer.handleGdbPacket(*this);
|
||||
}
|
||||
using ResponsePackets::ResponsePacket;
|
||||
using ResponsePackets::OkResponsePacket;
|
||||
using ResponsePackets::ErrorResponsePacket;
|
||||
|
||||
using Exceptions::Exception;
|
||||
|
||||
void WriteRegister::init() {
|
||||
// The P packet updates a single register
|
||||
@@ -28,4 +37,41 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
this->registerValue = Packet::hexToData(packetSegments.back().toStdString());
|
||||
std::reverse(this->registerValue.begin(), this->registerValue.end());
|
||||
}
|
||||
|
||||
void WriteRegister::handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) {
|
||||
Logger::debug("Handling WriteRegister packet");
|
||||
|
||||
try {
|
||||
auto targetRegisterDescriptor = debugSession.targetDescriptor.getTargetRegisterDescriptorFromNumber(this->registerNumber);
|
||||
|
||||
const auto valueSize = this->registerValue.size();
|
||||
if (valueSize > 0 && valueSize > targetRegisterDescriptor.size) {
|
||||
// Attempt to trim the higher zero-value bytes from the register value, until we reach the correct size.
|
||||
for (auto i = this->registerValue.size() - 1; i >= targetRegisterDescriptor.size; i--) {
|
||||
if (this->registerValue.at(i) != 0x00) {
|
||||
// If we reach a non-zero byte, we cannot trim anymore without changing the data
|
||||
break;
|
||||
}
|
||||
|
||||
this->registerValue.erase(this->registerValue.begin() + i);
|
||||
}
|
||||
|
||||
if (this->registerValue.size() > targetRegisterDescriptor.size) {
|
||||
const auto& gdbRegisterDescriptor = debugSession.targetDescriptor.getRegisterDescriptorFromNumber(this->registerNumber);
|
||||
throw Exception("Cannot set value for " + gdbRegisterDescriptor.name
|
||||
+ " - value size exceeds register size."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
targetControllerConsole.writeRegisters({
|
||||
TargetRegister(targetRegisterDescriptor, this->registerValue)
|
||||
});
|
||||
debugSession.connection.writePacket(OkResponsePacket());
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to write registers - " + exception.getMessage());
|
||||
debugSession.connection.writePacket(ErrorResponsePacket());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Bloom::DebugServers::Gdb::CommandPackets
|
||||
init();
|
||||
};
|
||||
|
||||
void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override;
|
||||
void handle(DebugSession& debugSession, TargetControllerConsole& targetControllerConsole) override;
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
@@ -23,16 +23,9 @@ namespace Bloom::DebugServers::Gdb
|
||||
class Connection
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* When the GDB client is waiting for the target to reach a breakpoint, this is set to true so we know when to
|
||||
* notify the client.
|
||||
*
|
||||
* @TODO: This is pretty gross. Consider rethinking it.
|
||||
*/
|
||||
bool waitingForBreak = false;
|
||||
|
||||
explicit Connection(std::shared_ptr<EventNotifier> interruptEventNotifier)
|
||||
: interruptEventNotifier(std::move(interruptEventNotifier)) {};
|
||||
: interruptEventNotifier(std::move(interruptEventNotifier))
|
||||
{};
|
||||
|
||||
/**
|
||||
* Accepts a connection on serverSocketFileDescriptor.
|
||||
|
||||
@@ -26,264 +26,6 @@ namespace Bloom::DebugServers::Gdb
|
||||
using Bloom::Targets::TargetRegisterDescriptors;
|
||||
using Bloom::Targets::TargetBreakpoint;
|
||||
|
||||
void GdbRspDebugServer::handleGdbPacket(CommandPacket& packet) {
|
||||
auto packetData = packet.getData();
|
||||
auto packetString = std::string(packetData.begin(), packetData.end());
|
||||
|
||||
if (packetString[0] == '?') {
|
||||
// Status report
|
||||
this->clientConnection->writePacket(TargetStopped(Signal::TRAP));
|
||||
|
||||
} else if (packetString[0] == 'D') {
|
||||
// Detach packet - there's not really anything we need to do here, so just respond with an OK
|
||||
this->clientConnection->writePacket(ResponsePacket({'O', 'K'}));
|
||||
|
||||
} else if (packetString.find("qAttached") == 0) {
|
||||
Logger::debug("Handling qAttached");
|
||||
this->clientConnection->writePacket(ResponsePacket({1}));
|
||||
|
||||
} else {
|
||||
Logger::debug("Unknown GDB RSP packet: " + packetString + " - returning empty response");
|
||||
|
||||
// Respond with an empty packet
|
||||
this->clientConnection->writePacket(ResponsePacket({0}));
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::handleGdbPacket(CommandPackets::SupportedFeaturesQuery& packet) {
|
||||
Logger::debug("Handling QuerySupport packet");
|
||||
|
||||
if (!packet.isFeatureSupported(Feature::HARDWARE_BREAKPOINTS)
|
||||
&& !packet.isFeatureSupported(Feature::SOFTWARE_BREAKPOINTS)
|
||||
) {
|
||||
// All GDB clients are expected to support breakpoints!
|
||||
throw ClientNotSupported("GDB client does not support HW or SW breakpoints");
|
||||
}
|
||||
|
||||
// Respond with a SupportedFeaturesResponse packet, listing all supported GDB features by Bloom
|
||||
auto response = ResponsePackets::SupportedFeaturesResponse({
|
||||
{Feature::SOFTWARE_BREAKPOINTS, std::nullopt},
|
||||
{Feature::PACKET_SIZE, std::to_string(this->clientConnection->getMaxPacketSize())},
|
||||
});
|
||||
|
||||
this->clientConnection->writePacket(response);
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::handleGdbPacket(CommandPackets::ReadRegisters& packet) {
|
||||
Logger::debug("Handling ReadRegisters packet");
|
||||
|
||||
try {
|
||||
auto descriptors = TargetRegisterDescriptors();
|
||||
|
||||
if (packet.registerNumber.has_value()) {
|
||||
Logger::debug("Reading register number: " + std::to_string(packet.registerNumber.value()));
|
||||
descriptors.insert(this->getTargetRegisterDescriptorFromNumber(packet.registerNumber.value()));
|
||||
|
||||
} else {
|
||||
// Read all target registers mapped to a GDB register
|
||||
for (const auto& descriptor : this->getRegisterNumberToDescriptorMapping().getMap()) {
|
||||
descriptors.insert(this->getTargetRegisterDescriptorFromNumber(descriptor.second.number));
|
||||
}
|
||||
}
|
||||
|
||||
auto registerSet = this->targetControllerConsole.readRegisters(descriptors);
|
||||
|
||||
/*
|
||||
* Sort each register by their respective GDB register number - this will leave us with a collection of
|
||||
* registers in the order expected by the GDB client.
|
||||
*/
|
||||
std::sort(
|
||||
registerSet.begin(),
|
||||
registerSet.end(),
|
||||
[this](const TargetRegister& registerA, const TargetRegister& registerB) {
|
||||
return this->getRegisterNumberFromTargetRegisterDescriptor(registerA.descriptor) <
|
||||
this->getRegisterNumberFromTargetRegisterDescriptor(registerB.descriptor);
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
* Finally, reverse the register values (as they're all currently in MSB, but GDB expects them in LSB), ensure
|
||||
* that each register value size matches the size in the associated GDB register descriptor, implode the
|
||||
* values, convert to hexadecimal form and send to the GDB client.
|
||||
*/
|
||||
auto registers = std::vector<unsigned char>();
|
||||
for (auto& reg : registerSet) {
|
||||
std::reverse(reg.value.begin(), reg.value.end());
|
||||
|
||||
const auto gdbRegisterNumber = this->getRegisterNumberFromTargetRegisterDescriptor(
|
||||
reg.descriptor
|
||||
).value();
|
||||
const auto& gdbRegisterDescriptor = this->getRegisterDescriptorFromNumber(gdbRegisterNumber);
|
||||
|
||||
if (reg.value.size() < gdbRegisterDescriptor.size) {
|
||||
reg.value.insert(reg.value.end(), (gdbRegisterDescriptor.size - reg.value.size()), 0x00);
|
||||
}
|
||||
|
||||
registers.insert(registers.end(), reg.value.begin(), reg.value.end());
|
||||
}
|
||||
|
||||
auto responseRegisters = Packet::dataToHex(registers);
|
||||
this->clientConnection->writePacket(
|
||||
ResponsePacket(std::vector<unsigned char>(responseRegisters.begin(), responseRegisters.end()))
|
||||
);
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to read general registers - " + exception.getMessage());
|
||||
this->clientConnection->writePacket(ResponsePacket({'E', '0', '1'}));
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::handleGdbPacket(CommandPackets::WriteRegister& packet) {
|
||||
Logger::debug("Handling WriteRegister packet");
|
||||
|
||||
try {
|
||||
auto targetRegisterDescriptor = this->getTargetRegisterDescriptorFromNumber(packet.registerNumber);
|
||||
|
||||
const auto valueSize = packet.registerValue.size();
|
||||
if (valueSize > 0 && valueSize > targetRegisterDescriptor.size) {
|
||||
// Attempt to trim the higher zero-value bytes from the register value, until we reach the correct size.
|
||||
for (auto i = packet.registerValue.size() - 1; i >= targetRegisterDescriptor.size; i--) {
|
||||
if (packet.registerValue.at(i) != 0x00) {
|
||||
// If we reach a non-zero byte, we cannot trim anymore without changing the data
|
||||
break;
|
||||
}
|
||||
|
||||
packet.registerValue.erase(packet.registerValue.begin() + i);
|
||||
}
|
||||
|
||||
if (packet.registerValue.size() > targetRegisterDescriptor.size) {
|
||||
const auto& gdbRegisterDescriptor = this->getRegisterDescriptorFromNumber(packet.registerNumber);
|
||||
throw Exception("Cannot set value for " + gdbRegisterDescriptor.name
|
||||
+ " - value size exceeds register size."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this->targetControllerConsole.writeRegisters({
|
||||
TargetRegister(targetRegisterDescriptor, packet.registerValue)
|
||||
});
|
||||
this->clientConnection->writePacket(ResponsePacket({'O', 'K'}));
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to write registers - " + exception.getMessage());
|
||||
this->clientConnection->writePacket(ResponsePacket({'E', '0', '1'}));
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::handleGdbPacket(CommandPackets::ContinueExecution& packet) {
|
||||
Logger::debug("Handling ContinueExecution packet");
|
||||
|
||||
try {
|
||||
this->targetControllerConsole.continueTargetExecution(packet.fromProgramCounter);
|
||||
this->clientConnection->waitingForBreak = true;
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to continue execution on target - " + exception.getMessage());
|
||||
this->clientConnection->writePacket(ResponsePacket({'E', '0', '1'}));
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::handleGdbPacket(CommandPackets::StepExecution& packet) {
|
||||
Logger::debug("Handling StepExecution packet");
|
||||
|
||||
try {
|
||||
this->targetControllerConsole.stepTargetExecution(packet.fromProgramCounter);
|
||||
this->clientConnection->waitingForBreak = true;
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to step execution on target - " + exception.getMessage());
|
||||
this->clientConnection->writePacket(ResponsePacket({'E', '0', '1'}));
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::handleGdbPacket(CommandPackets::ReadMemory& packet) {
|
||||
Logger::debug("Handling ReadMemory packet");
|
||||
|
||||
try {
|
||||
auto memoryType = this->getMemoryTypeFromGdbAddress(packet.startAddress);
|
||||
auto startAddress = this->removeMemoryTypeIndicatorFromGdbAddress(packet.startAddress);
|
||||
auto memoryBuffer = this->targetControllerConsole.readMemory(memoryType, startAddress, packet.bytes);
|
||||
|
||||
auto hexMemoryBuffer = Packet::dataToHex(memoryBuffer);
|
||||
this->clientConnection->writePacket(
|
||||
ResponsePacket(std::vector<unsigned char>(hexMemoryBuffer.begin(), hexMemoryBuffer.end()))
|
||||
);
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to read memory from target - " + exception.getMessage());
|
||||
this->clientConnection->writePacket(ResponsePacket({'E', '0', '1'}));
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::handleGdbPacket(CommandPackets::WriteMemory& packet) {
|
||||
Logger::debug("Handling WriteMemory packet");
|
||||
|
||||
try {
|
||||
const auto memoryType = this->getMemoryTypeFromGdbAddress(packet.startAddress);
|
||||
|
||||
if (memoryType == Targets::TargetMemoryType::FLASH) {
|
||||
throw Exception(
|
||||
"GDB client requested a flash memory write - This is not currently supported by Bloom."
|
||||
);
|
||||
}
|
||||
|
||||
const auto startAddress = this->removeMemoryTypeIndicatorFromGdbAddress(packet.startAddress);
|
||||
this->targetControllerConsole.writeMemory(memoryType, startAddress, packet.buffer);
|
||||
|
||||
this->clientConnection->writePacket(ResponsePacket({'O', 'K'}));
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to write memory to target - " + exception.getMessage());
|
||||
this->clientConnection->writePacket(ResponsePacket({'E', '0', '1'}));
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::handleGdbPacket(CommandPackets::SetBreakpoint& packet) {
|
||||
Logger::debug("Handling SetBreakpoint packet");
|
||||
|
||||
try {
|
||||
auto breakpoint = TargetBreakpoint();
|
||||
breakpoint.address = packet.address;
|
||||
this->targetControllerConsole.setBreakpoint(breakpoint);
|
||||
|
||||
this->clientConnection->writePacket(ResponsePacket({'O', 'K'}));
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to set breakpoint on target - " + exception.getMessage());
|
||||
this->clientConnection->writePacket(ResponsePacket({'E', '0', '1'}));
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::handleGdbPacket(CommandPackets::RemoveBreakpoint& packet) {
|
||||
Logger::debug("Removing breakpoint at address " + std::to_string(packet.address));
|
||||
|
||||
try {
|
||||
auto breakpoint = TargetBreakpoint();
|
||||
breakpoint.address = packet.address;
|
||||
this->targetControllerConsole.removeBreakpoint(breakpoint);
|
||||
|
||||
this->clientConnection->writePacket(ResponsePacket({'O', 'K'}));
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to remove breakpoint on target - " + exception.getMessage());
|
||||
this->clientConnection->writePacket(ResponsePacket({'E', '0', '1'}));
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::handleGdbPacket(CommandPackets::InterruptExecution& packet) {
|
||||
Logger::debug("Handling InterruptExecution packet");
|
||||
|
||||
try {
|
||||
this->targetControllerConsole.stopTargetExecution();
|
||||
this->clientConnection->writePacket(TargetStopped(Signal::INTERRUPTED));
|
||||
this->clientConnection->waitingForBreak = false;
|
||||
|
||||
} catch (const Exception& exception) {
|
||||
Logger::error("Failed to interrupt execution - " + exception.getMessage());
|
||||
this->clientConnection->writePacket(ResponsePacket({'E', '0', '1'}));
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::init() {
|
||||
this->debugServerConfig = GdbDebugServerConfig(DebugServer::debugServerConfig);
|
||||
|
||||
@@ -364,7 +106,7 @@ namespace Bloom::DebugServers::Gdb
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::close() {
|
||||
this->closeClientConnection();
|
||||
this->terminateActiveDebugSession();
|
||||
|
||||
if (this->serverSocketFileDescriptor > 0) {
|
||||
::close(this->serverSocketFileDescriptor);
|
||||
@@ -373,16 +115,20 @@ namespace Bloom::DebugServers::Gdb
|
||||
|
||||
void GdbRspDebugServer::serve() {
|
||||
try {
|
||||
if (!this->clientConnection.has_value()) {
|
||||
if (!this->activeDebugSession.has_value()) {
|
||||
Logger::info("Waiting for GDB RSP connection");
|
||||
|
||||
do {
|
||||
this->waitForConnection();
|
||||
auto connection = this->waitForConnection();
|
||||
|
||||
} while (!this->clientConnection.has_value());
|
||||
if (!connection.has_value()) {
|
||||
// Likely an interrupt
|
||||
return;
|
||||
}
|
||||
|
||||
this->clientConnection->accept(this->serverSocketFileDescriptor);
|
||||
Logger::info("Accepted GDP RSP connection from " + this->clientConnection->getIpAddress());
|
||||
connection->accept(this->serverSocketFileDescriptor);
|
||||
Logger::info("Accepted GDP RSP connection from " + connection->getIpAddress());
|
||||
|
||||
this->activeDebugSession = DebugSession(connection.value(), this->getGdbTargetDescriptor());
|
||||
EventManager::triggerEvent(std::make_shared<Events::DebugSessionStarted>());
|
||||
|
||||
/*
|
||||
@@ -390,39 +136,39 @@ namespace Bloom::DebugServers::Gdb
|
||||
* service it.
|
||||
*/
|
||||
if (!this->targetControllerConsole.isTargetControllerInService()) {
|
||||
this->closeClientConnection();
|
||||
this->terminateActiveDebugSession();
|
||||
throw DebugSessionAborted("TargetController not in service");
|
||||
}
|
||||
}
|
||||
|
||||
auto packets = this->clientConnection->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);
|
||||
}
|
||||
// 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);
|
||||
// }
|
||||
|
||||
} catch (const ClientDisconnected&) {
|
||||
Logger::info("GDB RSP client disconnected");
|
||||
this->closeClientConnection();
|
||||
this->terminateActiveDebugSession();
|
||||
return;
|
||||
|
||||
} catch (const ClientCommunicationError& exception) {
|
||||
Logger::error(
|
||||
"GDB RSP client communication error - " + exception.getMessage() + " - closing connection"
|
||||
);
|
||||
this->closeClientConnection();
|
||||
this->terminateActiveDebugSession();
|
||||
return;
|
||||
|
||||
} catch (const ClientNotSupported& exception) {
|
||||
Logger::error("Invalid GDB RSP client - " + exception.getMessage() + " - closing connection");
|
||||
this->closeClientConnection();
|
||||
this->terminateActiveDebugSession();
|
||||
return;
|
||||
|
||||
} catch (const DebugSessionAborted& exception) {
|
||||
Logger::warning("GDB debug session aborted - " + exception.getMessage());
|
||||
this->closeClientConnection();
|
||||
this->terminateActiveDebugSession();
|
||||
return;
|
||||
|
||||
} catch (const DebugServerInterrupted&) {
|
||||
@@ -432,7 +178,7 @@ namespace Bloom::DebugServers::Gdb
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::waitForConnection() {
|
||||
std::optional<Connection> GdbRspDebugServer::waitForConnection() {
|
||||
if (::listen(this->serverSocketFileDescriptor, 3) != 0) {
|
||||
throw Exception("Failed to listen on server socket");
|
||||
}
|
||||
@@ -453,25 +199,36 @@ namespace Bloom::DebugServers::Gdb
|
||||
if (fileDescriptor == this->interruptEventNotifier->getFileDescriptor()) {
|
||||
// Interrupted
|
||||
this->interruptEventNotifier->clear();
|
||||
throw DebugServerInterrupted();
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
this->clientConnection = Connection(this->interruptEventNotifier);
|
||||
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>());
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::onTargetControllerStateReported(const Events::TargetControllerStateReported& event) {
|
||||
if (event.state == TargetControllerState::SUSPENDED && this->clientConnection.has_value()) {
|
||||
if (event.state == TargetControllerState::SUSPENDED && this->activeDebugSession.has_value()) {
|
||||
Logger::warning("Terminating debug session - TargetController suspended unexpectedly");
|
||||
this->closeClientConnection();
|
||||
this->terminateActiveDebugSession();
|
||||
}
|
||||
}
|
||||
|
||||
void GdbRspDebugServer::onTargetExecutionStopped(const Events::TargetExecutionStopped&) {
|
||||
if (this->clientConnection.has_value() && this->clientConnection->waitingForBreak) {
|
||||
this->clientConnection->writePacket(TargetStopped(Signal::TRAP));
|
||||
this->clientConnection->waitingForBreak = false;
|
||||
if (this->activeDebugSession.has_value() && this->activeDebugSession->waitingForBreak) {
|
||||
this->activeDebugSession->connection.writePacket(TargetStopped(Signal::TRAP));
|
||||
this->activeDebugSession->waitingForBreak = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "GdbDebugServerConfig.hpp"
|
||||
|
||||
#include "Connection.hpp"
|
||||
#include "TargetDescriptor.hpp"
|
||||
#include "DebugSession.hpp"
|
||||
#include "Signal.hpp"
|
||||
#include "RegisterDescriptor.hpp"
|
||||
#include "Feature.hpp"
|
||||
@@ -51,85 +53,6 @@ namespace Bloom::DebugServers::Gdb
|
||||
return "GDB Remote Serial Protocol DebugServer";
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles any other GDB command packet that has not been promoted to a more specific type.
|
||||
* This would be packets like "?" and "qAttached".
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
virtual void handleGdbPacket(CommandPackets::CommandPacket& packet);
|
||||
|
||||
/**
|
||||
* Handles the supported features query ("qSupported") command packet.
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
virtual void handleGdbPacket(CommandPackets::SupportedFeaturesQuery& packet);
|
||||
|
||||
/**
|
||||
* Handles the read registers ("g" and "p") command packet.
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
virtual void handleGdbPacket(CommandPackets::ReadRegisters& packet);
|
||||
|
||||
/**
|
||||
* Handles the write general register ("P") command packet.
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
virtual void handleGdbPacket(CommandPackets::WriteRegister& packet);
|
||||
|
||||
/**
|
||||
* Handles the continue execution ("c") command packet.
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
virtual void handleGdbPacket(CommandPackets::ContinueExecution& packet);
|
||||
|
||||
/**
|
||||
* Handles the step execution ("s") packet.
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
virtual void handleGdbPacket(CommandPackets::StepExecution& packet);
|
||||
|
||||
/**
|
||||
* Handles the read memory ("m") command packet.
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
virtual void handleGdbPacket(CommandPackets::ReadMemory& packet);
|
||||
|
||||
/**
|
||||
* Handles the write memory ("M") command packet.
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
virtual void handleGdbPacket(CommandPackets::WriteMemory& packet);
|
||||
|
||||
/**
|
||||
* Handles the set breakpoint ("Z") command packet.
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
virtual void handleGdbPacket(CommandPackets::SetBreakpoint& packet);
|
||||
|
||||
/**
|
||||
* Handles the remove breakpoint ("z") command packet.
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
virtual void handleGdbPacket(CommandPackets::RemoveBreakpoint& packet);
|
||||
|
||||
/**
|
||||
* Handles the interrupt command packet.
|
||||
* Will attempt to halt execution on the target. Should respond with a "stop reply" packet, or an error code.
|
||||
*
|
||||
* @param packet
|
||||
*/
|
||||
virtual void handleGdbPacket(CommandPackets::InterruptExecution& packet);
|
||||
|
||||
protected:
|
||||
std::optional<GdbDebugServerConfig> debugServerConfig;
|
||||
|
||||
@@ -159,10 +82,7 @@ namespace Bloom::DebugServers::Gdb
|
||||
*/
|
||||
int enableReuseAddressSocketOption = 1;
|
||||
|
||||
/**
|
||||
* The current active GDB client connection, if any.
|
||||
*/
|
||||
std::optional<Connection> clientConnection;
|
||||
std::optional<DebugSession> activeDebugSession;
|
||||
|
||||
/**
|
||||
* Prepares the GDB server for listing on the selected address and port.
|
||||
@@ -180,72 +100,16 @@ namespace Bloom::DebugServers::Gdb
|
||||
void serve() override;
|
||||
|
||||
/**
|
||||
* Waits for a GDB client to connect on the listening socket. Accepts the connection and
|
||||
* sets this->clientConnection.
|
||||
*/
|
||||
void waitForConnection();
|
||||
|
||||
void closeClientConnection() {
|
||||
if (this->clientConnection.has_value()) {
|
||||
this->clientConnection->close();
|
||||
this->clientConnection = std::nullopt;
|
||||
EventManager::triggerEvent(std::make_shared<Events::DebugSessionFinished>());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GDB clients encode memory type information (flash, ram, eeprom, etc) in memory addresses. This is typically
|
||||
* hardcoded in the GDB client source. This method extracts memory type information from a given memory address.
|
||||
* The specifics of the encoding may vary with targets, which is why this method is virtual. For an example,
|
||||
* see the implementation of this method in AvrGdbRsp.
|
||||
* Waits for a GDB client to connect on the listening socket.
|
||||
*
|
||||
* @param address
|
||||
* @return
|
||||
* This function may return an std::nullopt, if the waiting was interrupted by some other event.
|
||||
*/
|
||||
virtual Targets::TargetMemoryType getMemoryTypeFromGdbAddress(std::uint32_t address) = 0;
|
||||
std::optional<Connection> waitForConnection();
|
||||
|
||||
/**
|
||||
* Removes memory type information from memory address.
|
||||
* See comment for GdbRspDebugServer::getMemoryTypeFromGdbAddress()
|
||||
*
|
||||
* @param address
|
||||
* @return
|
||||
*/
|
||||
virtual std::uint32_t removeMemoryTypeIndicatorFromGdbAddress(std::uint32_t address) = 0;
|
||||
void terminateActiveDebugSession();
|
||||
|
||||
/**
|
||||
* Should return the mapping of GDB register numbers to GDB register descriptors.
|
||||
*/
|
||||
virtual const BiMap<GdbRegisterNumberType, RegisterDescriptor>& getRegisterNumberToDescriptorMapping() = 0;
|
||||
virtual const TargetDescriptor& getGdbTargetDescriptor() = 0;
|
||||
|
||||
/**
|
||||
* Should retrieve the GDB register number, given a target register descriptor. Or std::nullopt if the target
|
||||
* register descriptor isn't mapped to any GDB register.
|
||||
*
|
||||
* @param registerDescriptor
|
||||
* @return
|
||||
*/
|
||||
virtual std::optional<GdbRegisterNumberType> getRegisterNumberFromTargetRegisterDescriptor(
|
||||
const Targets::TargetRegisterDescriptor& registerDescriptor
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Should retrieve the GDB register descriptor for a given GDB register number.
|
||||
*
|
||||
* @param number
|
||||
* @return
|
||||
*/
|
||||
virtual const RegisterDescriptor& getRegisterDescriptorFromNumber(GdbRegisterNumberType number) = 0;
|
||||
|
||||
/**
|
||||
* Should retrieve the mapped target register descriptor for a given GDB register number.
|
||||
*
|
||||
* @param number
|
||||
* @return
|
||||
*/
|
||||
virtual const Targets::TargetRegisterDescriptor& getTargetRegisterDescriptorFromNumber(
|
||||
GdbRegisterNumberType number
|
||||
) = 0;
|
||||
|
||||
void onTargetControllerStateReported(const Events::TargetControllerStateReported& event);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user