Refactored GDB server base class, making it a template class, allowing for much more flexibility for derived target-specific implementations
This commit is contained in:
@@ -4,7 +4,6 @@ target_sources(
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/DebugServerComponent.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/DebugServerComponent.cpp
|
||||||
|
|
||||||
# GDB RSP Server
|
# GDB RSP Server
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/GdbRspDebugServer.cpp
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/GdbDebugServerConfig.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/GdbDebugServerConfig.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/Connection.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/Connection.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/DebugSession.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/DebugSession.cpp
|
||||||
@@ -29,8 +28,7 @@ target_sources(
|
|||||||
|
|
||||||
# AVR GDB RSP Server
|
# AVR GDB RSP Server
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/AvrGdbRsp.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/AvrGdbRsp.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/TargetDescriptor.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/AvrGdbTargetDescriptor.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/DebugSession.cpp
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/CommandPackets/ReadRegisters.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/CommandPackets/ReadRegisters.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/CommandPackets/ReadRegister.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/CommandPackets/ReadRegister.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/CommandPackets/WriteRegister.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Gdb/AvrGdb/CommandPackets/WriteRegister.cpp
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
namespace DebugServer::Gdb::AvrGdb
|
namespace DebugServer::Gdb::AvrGdb
|
||||||
{
|
{
|
||||||
using namespace Exceptions;
|
using namespace Exceptions;
|
||||||
|
using namespace ::Exceptions;
|
||||||
|
|
||||||
using Targets::TargetRegisterDescriptor;
|
using Targets::TargetRegisterDescriptor;
|
||||||
using Targets::TargetRegisterType;
|
using Targets::TargetRegisterType;
|
||||||
@@ -33,33 +34,16 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
EventListener& eventListener,
|
EventListener& eventListener,
|
||||||
EventFdNotifier& eventNotifier
|
EventFdNotifier& eventNotifier
|
||||||
)
|
)
|
||||||
: GdbRspDebugServer(debugServerConfig, targetDescriptor, eventListener, eventNotifier)
|
: GdbRspDebugServer(
|
||||||
, gdbTargetDescriptor(targetDescriptor)
|
debugServerConfig,
|
||||||
|
targetDescriptor,
|
||||||
|
AvrGdbTargetDescriptor{targetDescriptor},
|
||||||
|
eventListener,
|
||||||
|
eventNotifier
|
||||||
|
)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
DebugSession* AvrGdbRsp::startDebugSession(Connection&& connection) {
|
std::unique_ptr<CommandPackets::CommandPacket> AvrGdbRsp::rawPacketToCommandPacket(const RawPacket& rawPacket) {
|
||||||
this->activeDebugSession.emplace(
|
|
||||||
std::move(connection),
|
|
||||||
this->getSupportedFeatures(),
|
|
||||||
this->debugServerConfig
|
|
||||||
);
|
|
||||||
|
|
||||||
return &*(this->activeDebugSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AvrGdbRsp::endDebugSession() {
|
|
||||||
this->activeDebugSession.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Gdb::TargetDescriptor& AvrGdbRsp::getGdbTargetDescriptor() {
|
|
||||||
return this->gdbTargetDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugSession* AvrGdbRsp::getActiveDebugSession() {
|
|
||||||
return this->activeDebugSession.has_value() ? &*(this->activeDebugSession) : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Gdb::CommandPackets::CommandPacket> AvrGdbRsp::resolveCommandPacket(const RawPacket& rawPacket) {
|
|
||||||
using Gdb::CommandPackets::Monitor;
|
using Gdb::CommandPackets::Monitor;
|
||||||
|
|
||||||
using CommandPackets::ReadRegister;
|
using CommandPackets::ReadRegister;
|
||||||
@@ -86,7 +70,7 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rawPacket[1] == 'g') {
|
if (rawPacket[1] == 'g') {
|
||||||
return std::make_unique<ReadRegisters>(rawPacket, this->gdbTargetDescriptor);
|
return std::make_unique<ReadRegisters>(rawPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rawPacket[1] == 'P') {
|
if (rawPacket[1] == 'P') {
|
||||||
@@ -105,11 +89,11 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
const auto rawPacketString = std::string{rawPacket.begin() + 1, rawPacket.end()};
|
const auto rawPacketString = std::string{rawPacket.begin() + 1, rawPacket.end()};
|
||||||
|
|
||||||
if (rawPacketString.find("qXfer:memory-map:read::") == 0) {
|
if (rawPacketString.find("qXfer:memory-map:read::") == 0) {
|
||||||
return std::make_unique<ReadMemoryMap>(rawPacket, this->gdbTargetDescriptor);
|
return std::make_unique<ReadMemoryMap>(rawPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rawPacketString.find("vFlashErase") == 0) {
|
if (rawPacketString.find("vFlashErase") == 0) {
|
||||||
return std::make_unique<FlashErase>(rawPacket, this->gdbTargetDescriptor);
|
return std::make_unique<FlashErase>(rawPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rawPacketString.find("vFlashWrite") == 0) {
|
if (rawPacketString.find("vFlashWrite") == 0) {
|
||||||
@@ -117,7 +101,7 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rawPacketString.find("vFlashDone") == 0) {
|
if (rawPacketString.find("vFlashDone") == 0) {
|
||||||
return std::make_unique<FlashDone>(rawPacket, this->gdbTargetDescriptor);
|
return std::make_unique<FlashDone>(rawPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rawPacketString.find("vCont?") == 0) {
|
if (rawPacketString.find("vCont?") == 0) {
|
||||||
@@ -134,7 +118,7 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
|
|
||||||
if (this->debugServerConfig.rangeStepping) {
|
if (this->debugServerConfig.rangeStepping) {
|
||||||
if (rawPacketString.find("vCont;r") == 0) {
|
if (rawPacketString.find("vCont;r") == 0) {
|
||||||
return std::make_unique<VContRangeStep>(rawPacket, this->gdbTargetDescriptor);
|
return std::make_unique<VContRangeStep>(rawPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,15 +127,12 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
auto monitorCommand = std::make_unique<Monitor>(rawPacket);
|
auto monitorCommand = std::make_unique<Monitor>(rawPacket);
|
||||||
|
|
||||||
if (monitorCommand->command.find("eeprom fill") == 0) {
|
if (monitorCommand->command.find("eeprom fill") == 0) {
|
||||||
return std::make_unique<EepromFill>(
|
return std::make_unique<EepromFill>(std::move(*(monitorCommand.release())));
|
||||||
std::move(*(monitorCommand.release())),
|
|
||||||
this->gdbTargetDescriptor
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return GdbRspDebugServer::resolveCommandPacket(rawPacket);
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::pair<Feature, std::optional<std::string>>> AvrGdbRsp::getSupportedFeatures() {
|
std::set<std::pair<Feature, std::optional<std::string>>> AvrGdbRsp::getSupportedFeatures() {
|
||||||
@@ -174,7 +155,7 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
|
|
||||||
Logger::debug("Target stopped at byte address: 0x" + StringService::toHex(programAddress));
|
Logger::debug("Target stopped at byte address: 0x" + StringService::toHex(programAddress));
|
||||||
|
|
||||||
auto& activeRangeSteppingSession = this->activeDebugSession->activeRangeSteppingSession;
|
auto& activeRangeSteppingSession = this->debugSession->activeRangeSteppingSession;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
activeRangeSteppingSession.has_value()
|
activeRangeSteppingSession.has_value()
|
||||||
@@ -186,7 +167,7 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
*
|
*
|
||||||
* We need to figure out why, and determine whether the stop should be reported to GDB.
|
* We need to figure out why, and determine whether the stop should be reported to GDB.
|
||||||
*/
|
*/
|
||||||
if (this->activeDebugSession->externalBreakpointsByAddress.contains(programAddress)) {
|
if (this->debugSession->externalBreakpointsByAddress.contains(programAddress)) {
|
||||||
/*
|
/*
|
||||||
* The target stopped due to an external breakpoint, set by GDB.
|
* The target stopped due to an external breakpoint, set by GDB.
|
||||||
*
|
*
|
||||||
@@ -194,7 +175,7 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
*/
|
*/
|
||||||
Logger::debug("Reached external breakpoint within stepping range");
|
Logger::debug("Reached external breakpoint within stepping range");
|
||||||
|
|
||||||
this->activeDebugSession->terminateRangeSteppingSession(this->targetControllerService);
|
this->debugSession->terminateRangeSteppingSession(this->targetControllerService);
|
||||||
return GdbRspDebugServer::handleTargetStoppedGdbResponse(programAddress);
|
return GdbRspDebugServer::handleTargetStoppedGdbResponse(programAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +217,7 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
* We have to end the range stepping session and report the stop to GDB.
|
* We have to end the range stepping session and report the stop to GDB.
|
||||||
*/
|
*/
|
||||||
Logger::debug("Target stopped within stepping range, but for an unknown reason");
|
Logger::debug("Target stopped within stepping range, but for an unknown reason");
|
||||||
this->activeDebugSession->terminateRangeSteppingSession(this->targetControllerService);
|
this->debugSession->terminateRangeSteppingSession(this->targetControllerService);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report the stop to GDB
|
// Report the stop to GDB
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "TargetDescriptor.hpp"
|
#include "AvrGdbTargetDescriptor.hpp"
|
||||||
#include "DebugSession.hpp"
|
#include "CommandPackets/CommandPacket.hpp"
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/GdbRspDebugServer.hpp"
|
#include "src/DebugServer/Gdb/GdbRspDebugServer.hpp"
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb
|
namespace DebugServer::Gdb::AvrGdb
|
||||||
{
|
{
|
||||||
class AvrGdbRsp: public GdbRspDebugServer
|
class AvrGdbRsp: public GdbRspDebugServer<AvrGdbTargetDescriptor, Gdb::DebugSession, CommandPackets::CommandPacket>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AvrGdbRsp(
|
AvrGdbRsp(
|
||||||
@@ -24,37 +24,8 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DebugSession* startDebugSession(Connection&& connection) override;
|
std::unique_ptr<CommandPackets::CommandPacket> rawPacketToCommandPacket(const RawPacket& rawPacket) override;
|
||||||
|
std::set<std::pair<Feature, std::optional<std::string>>> getSupportedFeatures() override;
|
||||||
void endDebugSession() override;
|
|
||||||
|
|
||||||
const Gdb::TargetDescriptor& getGdbTargetDescriptor() override;
|
|
||||||
|
|
||||||
DebugSession* getActiveDebugSession() override;
|
|
||||||
|
|
||||||
std::unique_ptr<Gdb::CommandPackets::CommandPacket> resolveCommandPacket(
|
|
||||||
const RawPacket& rawPacket
|
|
||||||
) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should return a set of GDB features supported by the AVR GDB server. Each supported feature may come with an
|
|
||||||
* optional value.
|
|
||||||
*
|
|
||||||
* The set of features returned by this function will be stored against the active debug session object.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
std::set<std::pair<Feature, std::optional<std::string>>> getSupportedFeatures();
|
|
||||||
|
|
||||||
void handleTargetStoppedGdbResponse(Targets::TargetMemoryAddress programAddress) override;
|
void handleTargetStoppedGdbResponse(Targets::TargetMemoryAddress programAddress) override;
|
||||||
|
|
||||||
private:
|
|
||||||
TargetDescriptor gdbTargetDescriptor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When a connection with a GDB client is established, a new instance of the DebugSession class is created and
|
|
||||||
* held here. A value of std::nullopt means there is no active debug session present.
|
|
||||||
*/
|
|
||||||
std::optional<DebugSession> activeDebugSession;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "TargetDescriptor.hpp"
|
#include "AvrGdbTargetDescriptor.hpp"
|
||||||
|
|
||||||
#include "src/Exceptions/Exception.hpp"
|
#include "src/Exceptions/Exception.hpp"
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
|
|
||||||
using Exceptions::Exception;
|
using Exceptions::Exception;
|
||||||
|
|
||||||
TargetDescriptor::TargetDescriptor(const Targets::TargetDescriptor& targetDescriptor)
|
AvrGdbTargetDescriptor::AvrGdbTargetDescriptor(const Targets::TargetDescriptor& targetDescriptor)
|
||||||
: programAddressSpaceDescriptor(targetDescriptor.getAddressSpaceDescriptor("prog"))
|
: programAddressSpaceDescriptor(targetDescriptor.getAddressSpaceDescriptor("prog"))
|
||||||
, eepromAddressSpaceDescriptor(targetDescriptor.getFirstAddressSpaceDescriptorContainingMemorySegment("internal_eeprom"))
|
, eepromAddressSpaceDescriptor(targetDescriptor.getFirstAddressSpaceDescriptorContainingMemorySegment("internal_eeprom"))
|
||||||
, sramAddressSpaceDescriptor(targetDescriptor.getAddressSpaceDescriptor("data"))
|
, sramAddressSpaceDescriptor(targetDescriptor.getAddressSpaceDescriptor("data"))
|
||||||
@@ -45,11 +45,11 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->gdbRegisterDescriptorsById.emplace(
|
this->gdbRegisterDescriptorsById.emplace(
|
||||||
TargetDescriptor::STATUS_GDB_REGISTER_ID,
|
AvrGdbTargetDescriptor::STATUS_GDB_REGISTER_ID,
|
||||||
RegisterDescriptor{TargetDescriptor::STATUS_GDB_REGISTER_ID, 1}
|
RegisterDescriptor{AvrGdbTargetDescriptor::STATUS_GDB_REGISTER_ID, 1}
|
||||||
);
|
);
|
||||||
this->targetRegisterDescriptorsByGdbId.emplace(
|
this->targetRegisterDescriptorsByGdbId.emplace(
|
||||||
TargetDescriptor::STATUS_GDB_REGISTER_ID,
|
AvrGdbTargetDescriptor::STATUS_GDB_REGISTER_ID,
|
||||||
&(targetDescriptor.getPeripheralDescriptor("cpu").getRegisterGroupDescriptor("cpu")
|
&(targetDescriptor.getPeripheralDescriptor("cpu").getRegisterGroupDescriptor("cpu")
|
||||||
.getRegisterDescriptor("sreg"))
|
.getRegisterDescriptor("sreg"))
|
||||||
);
|
);
|
||||||
@@ -60,45 +60,45 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
* CommandPackets::WriteRegister, etc for more.
|
* CommandPackets::WriteRegister, etc for more.
|
||||||
*/
|
*/
|
||||||
this->gdbRegisterDescriptorsById.emplace(
|
this->gdbRegisterDescriptorsById.emplace(
|
||||||
TargetDescriptor::STACK_POINTER_GDB_REGISTER_ID,
|
AvrGdbTargetDescriptor::STACK_POINTER_GDB_REGISTER_ID,
|
||||||
RegisterDescriptor{TargetDescriptor::STACK_POINTER_GDB_REGISTER_ID, 2}
|
RegisterDescriptor{AvrGdbTargetDescriptor::STACK_POINTER_GDB_REGISTER_ID, 2}
|
||||||
);
|
);
|
||||||
|
|
||||||
this->gdbRegisterDescriptorsById.emplace(
|
this->gdbRegisterDescriptorsById.emplace(
|
||||||
TargetDescriptor::PROGRAM_COUNTER_GDB_REGISTER_ID,
|
AvrGdbTargetDescriptor::PROGRAM_COUNTER_GDB_REGISTER_ID,
|
||||||
RegisterDescriptor{TargetDescriptor::PROGRAM_COUNTER_GDB_REGISTER_ID, 4}
|
RegisterDescriptor{AvrGdbTargetDescriptor::PROGRAM_COUNTER_GDB_REGISTER_ID, 4}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Targets::TargetAddressSpaceDescriptor& TargetDescriptor::addressSpaceDescriptorFromGdbAddress(
|
const Targets::TargetAddressSpaceDescriptor& AvrGdbTargetDescriptor::addressSpaceDescriptorFromGdbAddress(
|
||||||
GdbMemoryAddress address
|
GdbMemoryAddress address
|
||||||
) const {
|
) const {
|
||||||
if ((address & TargetDescriptor::EEPROM_ADDRESS_MASK) == TargetDescriptor::EEPROM_ADDRESS_MASK) {
|
if ((address & AvrGdbTargetDescriptor::EEPROM_ADDRESS_MASK) == AvrGdbTargetDescriptor::EEPROM_ADDRESS_MASK) {
|
||||||
return this->eepromAddressSpaceDescriptor;
|
return this->eepromAddressSpaceDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((address & TargetDescriptor::SRAM_ADDRESS_MASK) == TargetDescriptor::SRAM_ADDRESS_MASK) {
|
if ((address & AvrGdbTargetDescriptor::SRAM_ADDRESS_MASK) == AvrGdbTargetDescriptor::SRAM_ADDRESS_MASK) {
|
||||||
return this->sramAddressSpaceDescriptor;
|
return this->sramAddressSpaceDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->programAddressSpaceDescriptor;
|
return this->programAddressSpaceDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
Targets::TargetMemoryAddress TargetDescriptor::translateGdbAddress(GdbMemoryAddress address) const {
|
Targets::TargetMemoryAddress AvrGdbTargetDescriptor::translateGdbAddress(GdbMemoryAddress address) const {
|
||||||
if ((address & TargetDescriptor::EEPROM_ADDRESS_MASK) == TargetDescriptor::EEPROM_ADDRESS_MASK) {
|
if ((address & AvrGdbTargetDescriptor::EEPROM_ADDRESS_MASK) == AvrGdbTargetDescriptor::EEPROM_ADDRESS_MASK) {
|
||||||
// GDB sends EEPROM addresses in relative form - convert them to absolute form.
|
// GDB sends EEPROM addresses in relative form - convert them to absolute form.
|
||||||
return this->eepromMemorySegmentDescriptor.addressRange.startAddress
|
return this->eepromMemorySegmentDescriptor.addressRange.startAddress
|
||||||
+ (address & ~(TargetDescriptor::EEPROM_ADDRESS_MASK));
|
+ (address & ~(AvrGdbTargetDescriptor::EEPROM_ADDRESS_MASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((address & TargetDescriptor::SRAM_ADDRESS_MASK) == TargetDescriptor::SRAM_ADDRESS_MASK) {
|
if ((address & AvrGdbTargetDescriptor::SRAM_ADDRESS_MASK) == AvrGdbTargetDescriptor::SRAM_ADDRESS_MASK) {
|
||||||
return address & ~(TargetDescriptor::SRAM_ADDRESS_MASK);
|
return address & ~(AvrGdbTargetDescriptor::SRAM_ADDRESS_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
GdbMemoryAddress TargetDescriptor::translateTargetMemoryAddress(
|
GdbMemoryAddress AvrGdbTargetDescriptor::translateTargetMemoryAddress(
|
||||||
Targets::TargetMemoryAddress address,
|
Targets::TargetMemoryAddress address,
|
||||||
const Targets::TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
const Targets::TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
||||||
const Targets::TargetMemorySegmentDescriptor& memorySegmentDescriptor
|
const Targets::TargetMemorySegmentDescriptor& memorySegmentDescriptor
|
||||||
@@ -110,10 +110,10 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
if (memorySegmentDescriptor.type == Targets::TargetMemorySegmentType::EEPROM) {
|
if (memorySegmentDescriptor.type == Targets::TargetMemorySegmentType::EEPROM) {
|
||||||
// GDB expects EEPROM addresses in relative form
|
// GDB expects EEPROM addresses in relative form
|
||||||
return (address - memorySegmentDescriptor.addressRange.startAddress)
|
return (address - memorySegmentDescriptor.addressRange.startAddress)
|
||||||
| TargetDescriptor::EEPROM_ADDRESS_MASK;
|
| AvrGdbTargetDescriptor::EEPROM_ADDRESS_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We assume everything else is SRAM
|
// We assume everything else is SRAM
|
||||||
return address | TargetDescriptor::SRAM_ADDRESS_MASK;
|
return address | AvrGdbTargetDescriptor::SRAM_ADDRESS_MASK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb
|
namespace DebugServer::Gdb::AvrGdb
|
||||||
{
|
{
|
||||||
class TargetDescriptor: public DebugServer::Gdb::TargetDescriptor
|
class AvrGdbTargetDescriptor: public DebugServer::Gdb::TargetDescriptor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static constexpr auto SRAM_ADDRESS_MASK = 0x00800000U;
|
static constexpr auto SRAM_ADDRESS_MASK = 0x00800000U;
|
||||||
@@ -33,7 +33,7 @@ namespace DebugServer::Gdb::AvrGdb
|
|||||||
const Targets::TargetPeripheralDescriptor& cpuGpPeripheralDescriptor;
|
const Targets::TargetPeripheralDescriptor& cpuGpPeripheralDescriptor;
|
||||||
const Targets::TargetRegisterGroupDescriptor& cpuGpRegisterGroupDescriptor;
|
const Targets::TargetRegisterGroupDescriptor& cpuGpRegisterGroupDescriptor;
|
||||||
|
|
||||||
explicit TargetDescriptor(const Targets::TargetDescriptor& targetDescriptor);
|
explicit AvrGdbTargetDescriptor(const Targets::TargetDescriptor& targetDescriptor);
|
||||||
|
|
||||||
const Targets::TargetAddressSpaceDescriptor& addressSpaceDescriptorFromGdbAddress(
|
const Targets::TargetAddressSpaceDescriptor& addressSpaceDescriptorFromGdbAddress(
|
||||||
GdbMemoryAddress address
|
GdbMemoryAddress address
|
||||||
39
src/DebugServer/Gdb/AvrGdb/CommandPackets/CommandPacket.hpp
Normal file
39
src/DebugServer/Gdb/AvrGdb/CommandPackets/CommandPacket.hpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
||||||
|
#include "src/DebugServer/Gdb/DebugSession.hpp"
|
||||||
|
#include "src/DebugServer/Gdb/AvrGdb/AvrGdbTargetDescriptor.hpp"
|
||||||
|
#include "src/Targets/TargetDescriptor.hpp"
|
||||||
|
#include "src/Services/TargetControllerService.hpp"
|
||||||
|
|
||||||
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
||||||
|
{
|
||||||
|
class CommandPacket: public Gdb::CommandPackets::CommandPacket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CommandPacket(const RawPacket& rawPacket)
|
||||||
|
: Gdb::CommandPackets::CommandPacket(rawPacket)
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit CommandPacket(const Gdb::CommandPackets::CommandPacket& commandPacket)
|
||||||
|
: Gdb::CommandPackets::CommandPacket(commandPacket)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual ~CommandPacket() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should handle the command for the current active debug session.
|
||||||
|
*
|
||||||
|
* @param debugSession
|
||||||
|
* The current active debug session.
|
||||||
|
*
|
||||||
|
* @param TargetControllerService
|
||||||
|
*/
|
||||||
|
virtual void handle(
|
||||||
|
DebugSession& debugSession,
|
||||||
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
|
Services::TargetControllerService& targetControllerService
|
||||||
|
) = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -23,33 +23,31 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
using ::Exceptions::Exception;
|
using ::Exceptions::Exception;
|
||||||
using Exceptions::InvalidCommandOption;
|
using Exceptions::InvalidCommandOption;
|
||||||
|
|
||||||
EepromFill::EepromFill(Monitor&& monitorPacket, const TargetDescriptor& gdbTargetDescriptor)
|
EepromFill::EepromFill(Gdb::CommandPackets::Monitor&& monitorPacket)
|
||||||
: Monitor(std::move(monitorPacket))
|
: CommandPacket(monitorPacket)
|
||||||
, eepromAddressSpaceDescriptor(gdbTargetDescriptor.eepromAddressSpaceDescriptor)
|
, rawFillValue(monitorPacket.commandArguments.size() >= 3 ? monitorPacket.commandArguments[2] : std::string{})
|
||||||
, eepromMemorySegmentDescriptor(gdbTargetDescriptor.eepromMemorySegmentDescriptor)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void EepromFill::handle(
|
void EepromFill::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
Logger::info("Handling EepromFill packet");
|
Logger::info("Handling EepromFill packet");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (this->commandArguments.size() < 3 || this->commandArguments[2].empty()) {
|
if (this->rawFillValue.empty()) {
|
||||||
throw InvalidCommandOption{"Fill value required"};
|
throw InvalidCommandOption{"Fill value required"};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto eepromSize = this->eepromMemorySegmentDescriptor.size();
|
const auto eepromSize = gdbTargetDescriptor.eepromMemorySegmentDescriptor.size();
|
||||||
const auto& rawFillValue = this->commandArguments[2];
|
|
||||||
|
|
||||||
const auto fillValue = Services::StringService::dataFromHex(
|
const auto fillValue = Services::StringService::dataFromHex(
|
||||||
rawFillValue.size() >= 3 && rawFillValue[0] == '0'
|
this->rawFillValue.size() >= 3 && this->rawFillValue[0] == '0'
|
||||||
&& (rawFillValue[1] == 'X' || rawFillValue[1] == 'x')
|
&& (this->rawFillValue[1] == 'X' || this->rawFillValue[1] == 'x')
|
||||||
? rawFillValue.substr(2)
|
? this->rawFillValue.substr(2)
|
||||||
: rawFillValue
|
: this->rawFillValue
|
||||||
);
|
);
|
||||||
const auto fillValueSize = fillValue.size();
|
const auto fillValueSize = fillValue.size();
|
||||||
|
|
||||||
@@ -87,9 +85,9 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
Logger::debug("Filling EEPROM with values: " + hexValues);
|
Logger::debug("Filling EEPROM with values: " + hexValues);
|
||||||
|
|
||||||
targetControllerService.writeMemory(
|
targetControllerService.writeMemory(
|
||||||
this->eepromAddressSpaceDescriptor,
|
gdbTargetDescriptor.eepromAddressSpaceDescriptor,
|
||||||
this->eepromMemorySegmentDescriptor,
|
gdbTargetDescriptor.eepromMemorySegmentDescriptor,
|
||||||
this->eepromMemorySegmentDescriptor.addressRange.startAddress,
|
gdbTargetDescriptor.eepromMemorySegmentDescriptor.addressRange.startAddress,
|
||||||
std::move(data)
|
std::move(data)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "CommandPacket.hpp"
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/Monitor.hpp"
|
#include "src/DebugServer/Gdb/CommandPackets/Monitor.hpp"
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
|
|
||||||
|
|
||||||
#include "src/Targets/TargetAddressSpaceDescriptor.hpp"
|
|
||||||
#include "src/Targets/TargetMemorySegmentDescriptor.hpp"
|
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -16,17 +14,16 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
*
|
*
|
||||||
* This command fills the target's EEPROM with the given value.
|
* This command fills the target's EEPROM with the given value.
|
||||||
*/
|
*/
|
||||||
class EepromFill: public Gdb::CommandPackets::Monitor
|
class EepromFill: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const Targets::TargetAddressSpaceDescriptor& eepromAddressSpaceDescriptor;
|
std::string rawFillValue;
|
||||||
const Targets::TargetMemorySegmentDescriptor& eepromMemorySegmentDescriptor;
|
|
||||||
|
|
||||||
explicit EepromFill(Monitor&& monitorPacket, const TargetDescriptor& gdbTargetDescriptor);
|
explicit EepromFill(Gdb::CommandPackets::Monitor&& monitorPacket);
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
|
|||||||
@@ -15,15 +15,13 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
|
|
||||||
using namespace Exceptions;
|
using namespace Exceptions;
|
||||||
|
|
||||||
FlashDone::FlashDone(const RawPacket& rawPacket, const TargetDescriptor& targetDescriptor)
|
FlashDone::FlashDone(const RawPacket& rawPacket)
|
||||||
: CommandPacket(rawPacket)
|
: CommandPacket(rawPacket)
|
||||||
, programMemoryAddressSpaceDescriptor(targetDescriptor.programAddressSpaceDescriptor)
|
|
||||||
, programMemorySegmentDescriptor(targetDescriptor.programMemorySegmentDescriptor)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void FlashDone::handle(
|
void FlashDone::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
@@ -42,8 +40,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
targetControllerService.enableProgrammingMode();
|
targetControllerService.enableProgrammingMode();
|
||||||
|
|
||||||
targetControllerService.writeMemory(
|
targetControllerService.writeMemory(
|
||||||
this->programMemoryAddressSpaceDescriptor,
|
gdbTargetDescriptor.programAddressSpaceDescriptor,
|
||||||
this->programMemorySegmentDescriptor,
|
gdbTargetDescriptor.programMemorySegmentDescriptor,
|
||||||
debugSession.programmingSession->startAddress,
|
debugSession.programmingSession->startAddress,
|
||||||
std::move(debugSession.programmingSession->buffer)
|
std::move(debugSession.programmingSession->buffer)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,28 +3,21 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
|
|
||||||
|
|
||||||
#include "src/Targets/TargetAddressSpaceDescriptor.hpp"
|
|
||||||
#include "src/Targets/TargetMemorySegmentDescriptor.hpp"
|
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The FlashDone class implements the structure for the "vFlashDone" packet.
|
* The FlashDone class implements the structure for the "vFlashDone" packet.
|
||||||
*/
|
*/
|
||||||
class FlashDone: public Gdb::CommandPackets::CommandPacket
|
class FlashDone: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const Targets::TargetAddressSpaceDescriptor& programMemoryAddressSpaceDescriptor;
|
explicit FlashDone(const RawPacket& rawPacket);
|
||||||
const Targets::TargetMemorySegmentDescriptor& programMemorySegmentDescriptor;
|
|
||||||
|
|
||||||
explicit FlashDone(const RawPacket& rawPacket, const TargetDescriptor& targetDescriptor);
|
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
|
|||||||
@@ -16,10 +16,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
|
|
||||||
using namespace Exceptions;
|
using namespace Exceptions;
|
||||||
|
|
||||||
FlashErase::FlashErase(const RawPacket& rawPacket, const TargetDescriptor& targetDescriptor)
|
FlashErase::FlashErase(const RawPacket& rawPacket)
|
||||||
: CommandPacket(rawPacket)
|
: CommandPacket(rawPacket)
|
||||||
, programMemoryAddressSpaceDescriptor(targetDescriptor.programAddressSpaceDescriptor)
|
|
||||||
, programMemorySegmentDescriptor(targetDescriptor.programMemorySegmentDescriptor)
|
|
||||||
{
|
{
|
||||||
using Services::StringService;
|
using Services::StringService;
|
||||||
|
|
||||||
@@ -45,8 +43,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FlashErase::handle(
|
void FlashErase::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
@@ -59,8 +57,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
|
|
||||||
// We don't erase a specific address range - we just erase the entire program memory.
|
// We don't erase a specific address range - we just erase the entire program memory.
|
||||||
targetControllerService.eraseMemory(
|
targetControllerService.eraseMemory(
|
||||||
this->programMemoryAddressSpaceDescriptor,
|
gdbTargetDescriptor.programAddressSpaceDescriptor,
|
||||||
this->programMemorySegmentDescriptor
|
gdbTargetDescriptor.programMemorySegmentDescriptor
|
||||||
);
|
);
|
||||||
|
|
||||||
debugSession.connection.writePacket(OkResponsePacket{});
|
debugSession.connection.writePacket(OkResponsePacket{});
|
||||||
|
|||||||
@@ -3,11 +3,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
|
|
||||||
|
|
||||||
#include "src/Targets/TargetAddressSpaceDescriptor.hpp"
|
|
||||||
#include "src/Targets/TargetMemorySegmentDescriptor.hpp"
|
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
||||||
{
|
{
|
||||||
@@ -15,19 +11,17 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
* The FlashErase class implements the structure for the "vFlashErase" packet. Upon receiving this packet, the
|
* The FlashErase class implements the structure for the "vFlashErase" packet. Upon receiving this packet, the
|
||||||
* server is expected to erase a particular region of the target's flash memory.
|
* server is expected to erase a particular region of the target's flash memory.
|
||||||
*/
|
*/
|
||||||
class FlashErase: public Gdb::CommandPackets::CommandPacket
|
class FlashErase: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::uint32_t startAddress = 0;
|
std::uint32_t startAddress = 0;
|
||||||
std::uint32_t bytes = 0;
|
std::uint32_t bytes = 0;
|
||||||
const Targets::TargetAddressSpaceDescriptor& programMemoryAddressSpaceDescriptor;
|
|
||||||
const Targets::TargetMemorySegmentDescriptor& programMemorySegmentDescriptor;
|
|
||||||
|
|
||||||
explicit FlashErase(const RawPacket& rawPacket, const TargetDescriptor& targetDescriptor);
|
explicit FlashErase(const RawPacket& rawPacket);
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FlashWrite::handle(
|
void FlashWrite::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -3,8 +3,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
#include "src/DebugServer/Gdb/TargetDescriptor.hpp"
|
|
||||||
|
|
||||||
#include "src/Targets/TargetMemory.hpp"
|
#include "src/Targets/TargetMemory.hpp"
|
||||||
|
|
||||||
@@ -14,17 +13,17 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
* The FlashWrite class implements the structure for the "vFlashWrite" packet. Upon receiving this packet, the
|
* The FlashWrite class implements the structure for the "vFlashWrite" packet. Upon receiving this packet, the
|
||||||
* server is expected to write to a particular region of the target's flash memory.
|
* server is expected to write to a particular region of the target's flash memory.
|
||||||
*/
|
*/
|
||||||
class FlashWrite: public Gdb::CommandPackets::CommandPacket
|
class FlashWrite: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::uint32_t startAddress = 0;
|
Targets::TargetMemoryAddress startAddress;
|
||||||
Targets::TargetMemoryBuffer buffer;
|
Targets::TargetMemoryBuffer buffer;
|
||||||
|
|
||||||
explicit FlashWrite(const RawPacket& rawPacket);
|
explicit FlashWrite(const RawPacket& rawPacket);
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
|
|
||||||
using Exceptions::Exception;
|
using Exceptions::Exception;
|
||||||
|
|
||||||
ReadMemory::ReadMemory(const RawPacket& rawPacket, const TargetDescriptor& gdbTargetDescriptor)
|
ReadMemory::ReadMemory(const RawPacket& rawPacket, const AvrGdbTargetDescriptor& gdbTargetDescriptor)
|
||||||
: ReadMemory(rawPacket, gdbTargetDescriptor, ReadMemory::extractPacketData(rawPacket))
|
: ReadMemory(rawPacket, gdbTargetDescriptor, ReadMemory::extractPacketData(rawPacket))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void ReadMemory::handle(
|
void ReadMemory::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
@@ -147,7 +147,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
|
|
||||||
ReadMemory::ReadMemory(
|
ReadMemory::ReadMemory(
|
||||||
const RawPacket& rawPacket,
|
const RawPacket& rawPacket,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
ReadMemory::PacketData&& packetData
|
ReadMemory::PacketData&& packetData
|
||||||
)
|
)
|
||||||
: CommandPacket(rawPacket)
|
: CommandPacket(rawPacket)
|
||||||
|
|||||||
@@ -3,11 +3,10 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
|
|
||||||
#include "src/Targets/TargetAddressSpaceDescriptor.hpp"
|
#include "src/Targets/TargetAddressSpaceDescriptor.hpp"
|
||||||
#include "src/Targets/TargetMemory.hpp"
|
#include "src/Targets/TargetMemory.hpp"
|
||||||
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
|
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
||||||
{
|
{
|
||||||
@@ -15,7 +14,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
* The ReadMemory class implements a structure for "m" packets. Upon receiving these packets, the server is
|
* 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.
|
* expected to read memory from the target and send it the client.
|
||||||
*/
|
*/
|
||||||
class ReadMemory: public Gdb::CommandPackets::CommandPacket
|
class ReadMemory: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const Targets::TargetAddressSpaceDescriptor& addressSpaceDescriptor;
|
const Targets::TargetAddressSpaceDescriptor& addressSpaceDescriptor;
|
||||||
@@ -23,11 +22,11 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
Targets::TargetMemoryAddress startAddress;
|
Targets::TargetMemoryAddress startAddress;
|
||||||
Targets::TargetMemorySize bytes;
|
Targets::TargetMemorySize bytes;
|
||||||
|
|
||||||
ReadMemory(const RawPacket& rawPacket, const TargetDescriptor& gdbTargetDescriptor);
|
ReadMemory(const RawPacket& rawPacket, const AvrGdbTargetDescriptor& gdbTargetDescriptor);
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
@@ -42,7 +41,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
static PacketData extractPacketData(const RawPacket& rawPacket);
|
static PacketData extractPacketData(const RawPacket& rawPacket);
|
||||||
ReadMemory(
|
ReadMemory(
|
||||||
const RawPacket& rawPacket,
|
const RawPacket& rawPacket,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
PacketData&& packetData
|
PacketData&& packetData
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,11 +13,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
|
|
||||||
using Exceptions::Exception;
|
using Exceptions::Exception;
|
||||||
|
|
||||||
ReadMemoryMap::ReadMemoryMap(const RawPacket& rawPacket, const TargetDescriptor& gdbTargetDescriptor)
|
ReadMemoryMap::ReadMemoryMap(const RawPacket& rawPacket)
|
||||||
: CommandPacket(rawPacket)
|
: CommandPacket(rawPacket)
|
||||||
, eepromAddressSpaceDescriptor(gdbTargetDescriptor.eepromAddressSpaceDescriptor)
|
|
||||||
, programMemorySegmentDescriptor(gdbTargetDescriptor.programMemorySegmentDescriptor)
|
|
||||||
, eepromMemorySegmentDescriptor(gdbTargetDescriptor.eepromMemorySegmentDescriptor)
|
|
||||||
{
|
{
|
||||||
using Services::StringService;
|
using Services::StringService;
|
||||||
|
|
||||||
@@ -41,8 +38,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ReadMemoryMap::handle(
|
void ReadMemoryMap::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
@@ -53,18 +50,18 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
* data via memory read/write packets.
|
* data via memory read/write packets.
|
||||||
*/
|
*/
|
||||||
const auto ramSectionEndAddress = gdbTargetDescriptor.translateTargetMemoryAddress(
|
const auto ramSectionEndAddress = gdbTargetDescriptor.translateTargetMemoryAddress(
|
||||||
this->eepromMemorySegmentDescriptor.addressRange.endAddress,
|
gdbTargetDescriptor.eepromMemorySegmentDescriptor.addressRange.endAddress,
|
||||||
this->eepromAddressSpaceDescriptor,
|
gdbTargetDescriptor.eepromAddressSpaceDescriptor,
|
||||||
this->eepromMemorySegmentDescriptor
|
gdbTargetDescriptor.eepromMemorySegmentDescriptor
|
||||||
);
|
);
|
||||||
const auto ramSectionStartAddress = TargetDescriptor::SRAM_ADDRESS_MASK;
|
const auto ramSectionStartAddress = AvrGdbTargetDescriptor::SRAM_ADDRESS_MASK;
|
||||||
const auto ramSectionSize = ramSectionEndAddress - ramSectionStartAddress + 1;
|
const auto ramSectionSize = ramSectionEndAddress - ramSectionStartAddress + 1;
|
||||||
|
|
||||||
const auto memoryMap =
|
const auto memoryMap =
|
||||||
std::string{"<memory-map>"}
|
std::string{"<memory-map>"}
|
||||||
+ "<memory type=\"ram\" start=\"" + std::to_string(ramSectionStartAddress) + "\" length=\"" + std::to_string(ramSectionSize) + "\"/>"
|
+ "<memory type=\"ram\" start=\"" + std::to_string(ramSectionStartAddress) + "\" length=\"" + std::to_string(ramSectionSize) + "\"/>"
|
||||||
+ "<memory type=\"flash\" start=\"0\" length=\"" + std::to_string(this->programMemorySegmentDescriptor.size()) + "\">"
|
+ "<memory type=\"flash\" start=\"0\" length=\"" + std::to_string(gdbTargetDescriptor.programMemorySegmentDescriptor.size()) + "\">"
|
||||||
+ "<property name=\"blocksize\">" + std::to_string(this->programMemorySegmentDescriptor.pageSize.value()) + "</property>"
|
+ "<property name=\"blocksize\">" + std::to_string(gdbTargetDescriptor.programMemorySegmentDescriptor.pageSize.value()) + "</property>"
|
||||||
+ "</memory>"
|
+ "</memory>"
|
||||||
+ "</memory-map>";
|
+ "</memory-map>";
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,7 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
|
|
||||||
|
|
||||||
#include "src/Targets/TargetAddressSpaceDescriptor.hpp"
|
|
||||||
#include "src/Targets/TargetMemorySegmentDescriptor.hpp"
|
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
||||||
{
|
{
|
||||||
@@ -14,13 +10,9 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
* The ReadMemoryMap class implements a structure for the "qXfer:memory-map:read::..." packet. Upon receiving this
|
* The ReadMemoryMap class implements a structure for the "qXfer:memory-map:read::..." packet. Upon receiving this
|
||||||
* packet, the server is expected to respond with the target's memory map.
|
* packet, the server is expected to respond with the target's memory map.
|
||||||
*/
|
*/
|
||||||
class ReadMemoryMap: public Gdb::CommandPackets::CommandPacket
|
class ReadMemoryMap: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const Targets::TargetAddressSpaceDescriptor& eepromAddressSpaceDescriptor;
|
|
||||||
const Targets::TargetMemorySegmentDescriptor& programMemorySegmentDescriptor;
|
|
||||||
const Targets::TargetMemorySegmentDescriptor& eepromMemorySegmentDescriptor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The offset of the memory map, from which to read.
|
* The offset of the memory map, from which to read.
|
||||||
*/
|
*/
|
||||||
@@ -31,11 +23,11 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
*/
|
*/
|
||||||
std::uint32_t length = 0;
|
std::uint32_t length = 0;
|
||||||
|
|
||||||
explicit ReadMemoryMap(const RawPacket& rawPacket, const TargetDescriptor& gdbTargetDescriptor);
|
explicit ReadMemoryMap(const RawPacket& rawPacket);
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include "src/Targets/TargetRegisterDescriptor.hpp"
|
#include "src/Targets/TargetRegisterDescriptor.hpp"
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
|
|
||||||
#include "src/Services/StringService.hpp"
|
#include "src/Services/StringService.hpp"
|
||||||
#include "src/Logger/Logger.hpp"
|
#include "src/Logger/Logger.hpp"
|
||||||
|
|
||||||
@@ -36,8 +35,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ReadRegister::handle(
|
void ReadRegister::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
@@ -46,7 +45,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
try {
|
try {
|
||||||
Logger::debug("Reading GDB register ID: " + std::to_string(this->registerId));
|
Logger::debug("Reading GDB register ID: " + std::to_string(this->registerId));
|
||||||
|
|
||||||
if (this->registerId == TargetDescriptor::PROGRAM_COUNTER_GDB_REGISTER_ID) {
|
if (this->registerId == AvrGdbTargetDescriptor::PROGRAM_COUNTER_GDB_REGISTER_ID) {
|
||||||
/*
|
/*
|
||||||
* GDB has requested the program counter. We can't access this in the same way as we do with other
|
* GDB has requested the program counter. We can't access this in the same way as we do with other
|
||||||
* registers.
|
* registers.
|
||||||
@@ -65,7 +64,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->registerId == TargetDescriptor::STACK_POINTER_GDB_REGISTER_ID) {
|
if (this->registerId == AvrGdbTargetDescriptor::STACK_POINTER_GDB_REGISTER_ID) {
|
||||||
/*
|
/*
|
||||||
* GDB has requested the program counter. We can't access this in the same way as we do with other
|
* GDB has requested the program counter. We can't access this in the same way as we do with other
|
||||||
* registers.
|
* registers.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/RegisterDescriptor.hpp"
|
#include "src/DebugServer/Gdb/RegisterDescriptor.hpp"
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
* The ReadRegister class implements a structure for the "p" command packet. In response to this packet, the server
|
* The ReadRegister class implements a structure for the "p" command packet. In response to this packet, the server
|
||||||
* is expected to send register values for the requested register.
|
* is expected to send register values for the requested register.
|
||||||
*/
|
*/
|
||||||
class ReadRegister: public Gdb::CommandPackets::CommandPacket
|
class ReadRegister: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GdbRegisterId registerId;
|
GdbRegisterId registerId;
|
||||||
@@ -18,8 +18,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
explicit ReadRegister(const RawPacket& rawPacket);
|
explicit ReadRegister(const RawPacket& rawPacket);
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
|
|||||||
@@ -22,14 +22,13 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
|
|
||||||
using Exceptions::Exception;
|
using Exceptions::Exception;
|
||||||
|
|
||||||
ReadRegisters::ReadRegisters(const RawPacket& rawPacket, const TargetDescriptor& gdbTargetDescriptor)
|
ReadRegisters::ReadRegisters(const RawPacket& rawPacket)
|
||||||
: CommandPacket(rawPacket)
|
: CommandPacket(rawPacket)
|
||||||
, gpRegistersMemorySegmentDescriptor(gdbTargetDescriptor.gpRegistersMemorySegmentDescriptor)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void ReadRegisters::handle(
|
void ReadRegisters::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
@@ -60,7 +59,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto bufferOffset = regDesc.startAddress
|
const auto bufferOffset = regDesc.startAddress
|
||||||
- this->gpRegistersMemorySegmentDescriptor.addressRange.startAddress;
|
- gdbTargetDescriptor.gpRegistersMemorySegmentDescriptor.addressRange.startAddress;
|
||||||
|
|
||||||
assert((buffer.size() - bufferOffset) >= regVal.size());
|
assert((buffer.size() - bufferOffset) >= regVal.size());
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/RegisterDescriptor.hpp"
|
#include "src/DebugServer/Gdb/RegisterDescriptor.hpp"
|
||||||
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
|
|
||||||
#include "src/Targets/TargetMemorySegmentDescriptor.hpp"
|
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
||||||
{
|
{
|
||||||
@@ -14,16 +12,14 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
* The ReadRegisters class implements a structure for the "g" command packet. In response to this packet, the
|
* The ReadRegisters class implements a structure for the "g" command packet. In response to this packet, the
|
||||||
* server is expected to send register values for all registers.
|
* server is expected to send register values for all registers.
|
||||||
*/
|
*/
|
||||||
class ReadRegisters: public Gdb::CommandPackets::CommandPacket
|
class ReadRegisters: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const Targets::TargetMemorySegmentDescriptor& gpRegistersMemorySegmentDescriptor;
|
explicit ReadRegisters(const RawPacket& rawPacket);
|
||||||
|
|
||||||
explicit ReadRegisters(const RawPacket& rawPacket, const TargetDescriptor& gdbTargetDescriptor);
|
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
void VContContinueExecution::handle(
|
void VContContinueExecution::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
||||||
{
|
{
|
||||||
@@ -10,14 +10,14 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
* The VContContinueExecution class implements a structure for "vCont;c" and "vCont;C" packets. These packets
|
* The VContContinueExecution class implements a structure for "vCont;c" and "vCont;C" packets. These packets
|
||||||
* instruct the server to continue execution on the target.
|
* instruct the server to continue execution on the target.
|
||||||
*/
|
*/
|
||||||
class VContContinueExecution: public Gdb::CommandPackets::CommandPacket
|
class VContContinueExecution: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit VContContinueExecution(const RawPacket& rawPacket);
|
explicit VContContinueExecution(const RawPacket& rawPacket);
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
|
|||||||
@@ -17,10 +17,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
using ResponsePackets::ErrorResponsePacket;
|
using ResponsePackets::ErrorResponsePacket;
|
||||||
using ::Exceptions::Exception;
|
using ::Exceptions::Exception;
|
||||||
|
|
||||||
VContRangeStep::VContRangeStep(const RawPacket& rawPacket, const TargetDescriptor& gdbTargetDescriptor)
|
VContRangeStep::VContRangeStep(const RawPacket& rawPacket)
|
||||||
: CommandPacket(rawPacket)
|
: CommandPacket(rawPacket)
|
||||||
, programAddressSpaceDescriptor(gdbTargetDescriptor.programAddressSpaceDescriptor)
|
|
||||||
, programMemorySegmentDescriptor(gdbTargetDescriptor.programMemorySegmentDescriptor)
|
|
||||||
{
|
{
|
||||||
using Services::StringService;
|
using Services::StringService;
|
||||||
|
|
||||||
@@ -44,8 +42,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VContRangeStep::handle(
|
void VContRangeStep::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
@@ -61,7 +59,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
try {
|
try {
|
||||||
const auto stepAddressRange = Targets::TargetMemoryAddressRange{this->startAddress, this->endAddress};
|
const auto stepAddressRange = Targets::TargetMemoryAddressRange{this->startAddress, this->endAddress};
|
||||||
const auto stepByteSize = stepAddressRange.size() - 1; // -1 because the end address is exclusive
|
const auto stepByteSize = stepAddressRange.size() - 1; // -1 because the end address is exclusive
|
||||||
const auto& programMemoryAddressRange = this->programMemorySegmentDescriptor.addressRange;
|
const auto& programMemoryAddressRange = gdbTargetDescriptor.programMemorySegmentDescriptor.addressRange;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
stepAddressRange.startAddress > stepAddressRange.endAddress
|
stepAddressRange.startAddress > stepAddressRange.endAddress
|
||||||
@@ -91,8 +89,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
const auto instructionsByAddress = Decoder::decode(
|
const auto instructionsByAddress = Decoder::decode(
|
||||||
stepAddressRange.startAddress,
|
stepAddressRange.startAddress,
|
||||||
targetControllerService.readMemory(
|
targetControllerService.readMemory(
|
||||||
this->programAddressSpaceDescriptor,
|
gdbTargetDescriptor.programAddressSpaceDescriptor,
|
||||||
this->programMemorySegmentDescriptor,
|
gdbTargetDescriptor.programMemorySegmentDescriptor,
|
||||||
stepAddressRange.startAddress,
|
stepAddressRange.startAddress,
|
||||||
stepByteSize
|
stepByteSize
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,11 +2,8 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
|
|
||||||
#include "src/Targets/TargetAddressSpaceDescriptor.hpp"
|
|
||||||
#include "src/Targets/TargetMemorySegmentDescriptor.hpp"
|
|
||||||
#include "src/Targets/TargetMemory.hpp"
|
#include "src/Targets/TargetMemory.hpp"
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
||||||
@@ -16,20 +13,17 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
* step through a particular address range, and only report back to GDB when execution leaves that range, or when an
|
* step through a particular address range, and only report back to GDB when execution leaves that range, or when an
|
||||||
* external breakpoint has been reached.
|
* external breakpoint has been reached.
|
||||||
*/
|
*/
|
||||||
class VContRangeStep: public Gdb::CommandPackets::CommandPacket
|
class VContRangeStep: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const Targets::TargetAddressSpaceDescriptor& programAddressSpaceDescriptor;
|
|
||||||
const Targets::TargetMemorySegmentDescriptor& programMemorySegmentDescriptor;
|
|
||||||
|
|
||||||
Targets::TargetMemoryAddress startAddress;
|
Targets::TargetMemoryAddress startAddress;
|
||||||
Targets::TargetMemoryAddress endAddress;
|
Targets::TargetMemoryAddress endAddress;
|
||||||
|
|
||||||
explicit VContRangeStep(const RawPacket& rawPacket, const TargetDescriptor& gdbTargetDescriptor);
|
explicit VContRangeStep(const RawPacket& rawPacket);
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
void VContStepExecution::handle(
|
void VContStepExecution::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -2,21 +2,21 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The VContStepExecution class implements a structure for "vCont;s" and "vCont;S" packets.
|
* The VContStepExecution class implements a structure for "vCont;s" and "vCont;S" packets.
|
||||||
*/
|
*/
|
||||||
class VContStepExecution: public Gdb::CommandPackets::CommandPacket
|
class VContStepExecution: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit VContStepExecution(const RawPacket& rawPacket);
|
explicit VContStepExecution(const RawPacket& rawPacket);
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
void VContSupportedActionsQuery::handle(
|
void VContSupportedActionsQuery::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
||||||
{
|
{
|
||||||
@@ -13,14 +13,14 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
*
|
*
|
||||||
* Responses to this command packet should take the form of a ResponsePackets::SupportedFeaturesResponse.
|
* Responses to this command packet should take the form of a ResponsePackets::SupportedFeaturesResponse.
|
||||||
*/
|
*/
|
||||||
class VContSupportedActionsQuery: public Gdb::CommandPackets::CommandPacket
|
class VContSupportedActionsQuery: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit VContSupportedActionsQuery(const RawPacket& rawPacket);
|
explicit VContSupportedActionsQuery(const RawPacket& rawPacket);
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
|
|
||||||
using namespace Exceptions;
|
using namespace Exceptions;
|
||||||
|
|
||||||
WriteMemory::WriteMemory(const RawPacket& rawPacket, const TargetDescriptor& gdbTargetDescriptor)
|
WriteMemory::WriteMemory(const RawPacket& rawPacket, const AvrGdbTargetDescriptor& gdbTargetDescriptor)
|
||||||
: WriteMemory(rawPacket, gdbTargetDescriptor, WriteMemory::extractPacketData(rawPacket))
|
: WriteMemory(rawPacket, gdbTargetDescriptor, WriteMemory::extractPacketData(rawPacket))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void WriteMemory::handle(
|
void WriteMemory::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
@@ -116,7 +116,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
|
|
||||||
WriteMemory::WriteMemory(
|
WriteMemory::WriteMemory(
|
||||||
const RawPacket& rawPacket,
|
const RawPacket& rawPacket,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
PacketData&& packetData
|
PacketData&& packetData
|
||||||
)
|
)
|
||||||
: CommandPacket(rawPacket)
|
: CommandPacket(rawPacket)
|
||||||
|
|||||||
@@ -3,11 +3,10 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
|
|
||||||
#include "src/Targets/TargetAddressSpaceDescriptor.hpp"
|
#include "src/Targets/TargetAddressSpaceDescriptor.hpp"
|
||||||
#include "src/Targets/TargetMemory.hpp"
|
#include "src/Targets/TargetMemory.hpp"
|
||||||
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
|
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
||||||
{
|
{
|
||||||
@@ -15,7 +14,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
* The WriteMemory class implements the structure for "M" packets. Upon receiving this packet, the server is
|
* 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.
|
* expected to write data to the target's memory, at the specified start address.
|
||||||
*/
|
*/
|
||||||
class WriteMemory: public Gdb::CommandPackets::CommandPacket
|
class WriteMemory: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const Targets::TargetAddressSpaceDescriptor& addressSpaceDescriptor;
|
const Targets::TargetAddressSpaceDescriptor& addressSpaceDescriptor;
|
||||||
@@ -23,11 +22,11 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
Targets::TargetMemorySize bytes;
|
Targets::TargetMemorySize bytes;
|
||||||
Targets::TargetMemoryBuffer buffer;
|
Targets::TargetMemoryBuffer buffer;
|
||||||
|
|
||||||
explicit WriteMemory(const RawPacket& rawPacket, const TargetDescriptor& gdbTargetDescriptor);
|
explicit WriteMemory(const RawPacket& rawPacket, const AvrGdbTargetDescriptor& gdbTargetDescriptor);
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
@@ -41,6 +40,6 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
};
|
};
|
||||||
|
|
||||||
static PacketData extractPacketData(const RawPacket& rawPacket);
|
static PacketData extractPacketData(const RawPacket& rawPacket);
|
||||||
WriteMemory(const RawPacket& rawPacket, const Gdb::TargetDescriptor& gdbTargetDescriptor, PacketData&& packetData);
|
WriteMemory(const RawPacket& rawPacket, const AvrGdbTargetDescriptor& gdbTargetDescriptor, PacketData&& packetData);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,15 +46,15 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WriteRegister::handle(
|
void WriteRegister::handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
TargetControllerService& targetControllerService
|
TargetControllerService& targetControllerService
|
||||||
) {
|
) {
|
||||||
Logger::info("Handling WriteRegister packet");
|
Logger::info("Handling WriteRegister packet");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (this->registerId == TargetDescriptor::PROGRAM_COUNTER_GDB_REGISTER_ID) {
|
if (this->registerId == AvrGdbTargetDescriptor::PROGRAM_COUNTER_GDB_REGISTER_ID) {
|
||||||
if (this->registerValue.size() != 4) {
|
if (this->registerValue.size() != 4) {
|
||||||
throw Exception{"Invalid PC value register size"};
|
throw Exception{"Invalid PC value register size"};
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->registerId == TargetDescriptor::STACK_POINTER_GDB_REGISTER_ID) {
|
if (this->registerId == AvrGdbTargetDescriptor::STACK_POINTER_GDB_REGISTER_ID) {
|
||||||
if (this->registerValue.size() != 2) {
|
if (this->registerValue.size() != 2) {
|
||||||
throw Exception{"Invalid SP register value size"};
|
throw Exception{"Invalid SP register value size"};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/CommandPackets/CommandPacket.hpp"
|
#include "CommandPacket.hpp"
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/RegisterDescriptor.hpp"
|
#include "src/DebugServer/Gdb/RegisterDescriptor.hpp"
|
||||||
#include "src/DebugServer/Gdb/AvrGdb/TargetDescriptor.hpp"
|
|
||||||
|
|
||||||
#include "src/Targets/TargetMemory.hpp"
|
#include "src/Targets/TargetMemory.hpp"
|
||||||
|
|
||||||
@@ -12,7 +11,7 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
/**
|
/**
|
||||||
* The WriteRegister class implements the structure for "P" packets.
|
* The WriteRegister class implements the structure for "P" packets.
|
||||||
*/
|
*/
|
||||||
class WriteRegister: public Gdb::CommandPackets::CommandPacket
|
class WriteRegister: public CommandPackets::CommandPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GdbRegisterId registerId;
|
GdbRegisterId registerId;
|
||||||
@@ -21,8 +20,8 @@ namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|||||||
explicit WriteRegister(const RawPacket& rawPacket);
|
explicit WriteRegister(const RawPacket& rawPacket);
|
||||||
|
|
||||||
void handle(
|
void handle(
|
||||||
Gdb::DebugSession& debugSession,
|
DebugSession& debugSession,
|
||||||
const Gdb::TargetDescriptor& gdbTargetDescriptor,
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
Services::TargetControllerService& targetControllerService
|
Services::TargetControllerService& targetControllerService
|
||||||
) override;
|
) override;
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
#include "DebugSession.hpp"
|
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb
|
|
||||||
{
|
|
||||||
DebugSession::DebugSession(
|
|
||||||
Connection&& connection,
|
|
||||||
const std::set<std::pair<Feature, std::optional<std::string>>>& supportedFeatures,
|
|
||||||
const GdbDebugServerConfig& serverConfig
|
|
||||||
)
|
|
||||||
: Gdb::DebugSession(std::move(connection), supportedFeatures, serverConfig)
|
|
||||||
{}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "src/DebugServer/Gdb/DebugSession.hpp"
|
|
||||||
|
|
||||||
#include "TargetDescriptor.hpp"
|
|
||||||
|
|
||||||
namespace DebugServer::Gdb::AvrGdb
|
|
||||||
{
|
|
||||||
class DebugSession final: public Gdb::DebugSession
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DebugSession(
|
|
||||||
Connection&& connection,
|
|
||||||
const std::set<std::pair<Feature, std::optional<std::string>>>& supportedFeatures,
|
|
||||||
const GdbDebugServerConfig& serverConfig
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -14,6 +14,8 @@ namespace DebugServer::Gdb::CommandPackets
|
|||||||
public:
|
public:
|
||||||
explicit CommandPacket(const RawPacket& rawPacket);
|
explicit CommandPacket(const RawPacket& rawPacket);
|
||||||
|
|
||||||
|
virtual ~CommandPacket() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should handle the command for the current active debug session.
|
* Should handle the command for the current active debug session.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ namespace DebugServer::Gdb
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The current server configuration.
|
* The current server configuration.
|
||||||
|
*
|
||||||
|
* TODO: I think this should be moved out of the DebugSession struct and passed into CommandPacket::handle()
|
||||||
|
* function. Review after v1.1.0.
|
||||||
*/
|
*/
|
||||||
const GdbDebugServerConfig& serverConfig;
|
const GdbDebugServerConfig& serverConfig;
|
||||||
|
|
||||||
|
|||||||
@@ -1,397 +0,0 @@
|
|||||||
#include "GdbRspDebugServer.hpp"
|
|
||||||
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "src/EventManager/EventManager.hpp"
|
|
||||||
#include "src/Logger/Logger.hpp"
|
|
||||||
|
|
||||||
#include "Exceptions/ClientDisconnected.hpp"
|
|
||||||
#include "Exceptions/ClientNotSupported.hpp"
|
|
||||||
#include "Exceptions/ClientCommunicationError.hpp"
|
|
||||||
#include "Exceptions/DebugSessionInitialisationFailure.hpp"
|
|
||||||
#include "Exceptions/DebugServerInterrupted.hpp"
|
|
||||||
|
|
||||||
#include "src/Exceptions/Exception.hpp"
|
|
||||||
#include "src/Exceptions/InvalidConfig.hpp"
|
|
||||||
|
|
||||||
// Command packets
|
|
||||||
#include "CommandPackets/CommandPacket.hpp"
|
|
||||||
#include "CommandPackets/SupportedFeaturesQuery.hpp"
|
|
||||||
#include "CommandPackets/InterruptExecution.hpp"
|
|
||||||
#include "CommandPackets/ContinueExecution.hpp"
|
|
||||||
#include "CommandPackets/StepExecution.hpp"
|
|
||||||
#include "CommandPackets/SetBreakpoint.hpp"
|
|
||||||
#include "CommandPackets/RemoveBreakpoint.hpp"
|
|
||||||
#include "CommandPackets/Monitor.hpp"
|
|
||||||
#include "CommandPackets/ResetTarget.hpp"
|
|
||||||
#include "CommandPackets/HelpMonitorInfo.hpp"
|
|
||||||
#include "CommandPackets/BloomVersion.hpp"
|
|
||||||
#include "CommandPackets/BloomVersionMachine.hpp"
|
|
||||||
#include "CommandPackets/Detach.hpp"
|
|
||||||
#include "CommandPackets/ListRegistersMonitor.hpp"
|
|
||||||
#include "CommandPackets/ReadRegistersMonitor.hpp"
|
|
||||||
#include "CommandPackets/WriteRegisterMonitor.hpp"
|
|
||||||
|
|
||||||
#ifndef EXCLUDE_INSIGHT
|
|
||||||
#include "CommandPackets/ActivateInsight.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Response packets
|
|
||||||
#include "ResponsePackets/TargetStopped.hpp"
|
|
||||||
|
|
||||||
#include "src/Services/ProcessService.hpp"
|
|
||||||
#include "src/Services/StringService.hpp"
|
|
||||||
|
|
||||||
namespace DebugServer::Gdb
|
|
||||||
{
|
|
||||||
using namespace Exceptions;
|
|
||||||
using namespace ::Exceptions;
|
|
||||||
|
|
||||||
using CommandPackets::CommandPacket;
|
|
||||||
|
|
||||||
GdbRspDebugServer::GdbRspDebugServer(
|
|
||||||
const DebugServerConfig& debugServerConfig,
|
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
|
||||||
EventListener& eventListener,
|
|
||||||
EventFdNotifier& eventNotifier
|
|
||||||
)
|
|
||||||
: debugServerConfig(GdbDebugServerConfig(debugServerConfig))
|
|
||||||
, targetDescriptor(targetDescriptor)
|
|
||||||
, eventListener(eventListener)
|
|
||||||
, interruptEventNotifier(eventNotifier)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void GdbRspDebugServer::init() {
|
|
||||||
this->socketAddress.sin_family = AF_INET;
|
|
||||||
this->socketAddress.sin_port = htons(this->debugServerConfig.listeningPortNumber);
|
|
||||||
|
|
||||||
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 + "\")"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto socketFileDescriptor = int{0};
|
|
||||||
if ((socketFileDescriptor = ::socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
|
||||||
throw Exception{"Failed to create socket file descriptor."};
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto enableReuseAddressSocketOption = int{1};
|
|
||||||
if (
|
|
||||||
::setsockopt(
|
|
||||||
socketFileDescriptor,
|
|
||||||
SOL_SOCKET,
|
|
||||||
SO_REUSEADDR,
|
|
||||||
&(enableReuseAddressSocketOption),
|
|
||||||
sizeof(enableReuseAddressSocketOption)
|
|
||||||
) < 0
|
|
||||||
) {
|
|
||||||
Logger::error("Failed to set socket SO_REUSEADDR option.");
|
|
||||||
}
|
|
||||||
|
|
||||||
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."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
this->serverSocketFileDescriptor = socketFileDescriptor;
|
|
||||||
|
|
||||||
this->epollInstance.addEntry(
|
|
||||||
this->serverSocketFileDescriptor.value(),
|
|
||||||
static_cast<std::uint16_t>(::EPOLL_EVENTS::EPOLLIN)
|
|
||||||
);
|
|
||||||
|
|
||||||
this->epollInstance.addEntry(
|
|
||||||
this->interruptEventNotifier.getFileDescriptor(),
|
|
||||||
static_cast<std::uint16_t>(::EPOLL_EVENTS::EPOLLIN)
|
|
||||||
);
|
|
||||||
|
|
||||||
Logger::info("GDB RSP address: " + this->debugServerConfig.listeningAddress);
|
|
||||||
Logger::info("GDB RSP port: " + std::to_string(this->debugServerConfig.listeningPortNumber));
|
|
||||||
|
|
||||||
this->eventListener.registerCallbackForEventType<Events::TargetStateChanged>(
|
|
||||||
std::bind(&GdbRspDebugServer::onTargetStateChanged, this, std::placeholders::_1)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (Services::ProcessService::isManagedByClion()) {
|
|
||||||
Logger::warning(
|
|
||||||
"Bloom's process is being managed by CLion - Bloom will automatically shutdown upon detaching from GDB."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbRspDebugServer::close() {
|
|
||||||
this->endDebugSession();
|
|
||||||
|
|
||||||
if (this->serverSocketFileDescriptor.has_value()) {
|
|
||||||
::close(this->serverSocketFileDescriptor.value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbRspDebugServer::run() {
|
|
||||||
try {
|
|
||||||
if (this->getActiveDebugSession() == nullptr) {
|
|
||||||
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));
|
|
||||||
|
|
||||||
this->targetControllerService.stopTargetExecution();
|
|
||||||
this->targetControllerService.resetTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto commandPacket = this->waitForCommandPacket();
|
|
||||||
if (!commandPacket) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
commandPacket->handle(
|
|
||||||
*(this->getActiveDebugSession()),
|
|
||||||
this->getGdbTargetDescriptor(),
|
|
||||||
this->targetDescriptor,
|
|
||||||
this->targetControllerService
|
|
||||||
);
|
|
||||||
|
|
||||||
} 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 ClientNotSupported& exception) {
|
|
||||||
Logger::error("Invalid GDB RSP client - " + exception.getMessage() + " - closing connection");
|
|
||||||
this->endDebugSession();
|
|
||||||
return;
|
|
||||||
|
|
||||||
} catch (const DebugSessionInitialisationFailure& exception) {
|
|
||||||
Logger::warning("GDB debug session initialisation failure - " + exception.getMessage());
|
|
||||||
this->endDebugSession();
|
|
||||||
return;
|
|
||||||
|
|
||||||
} catch (const DebugServerInterrupted&) {
|
|
||||||
// Server was interrupted by an event
|
|
||||||
Logger::debug("GDB RSP interrupted");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connection GdbRspDebugServer::waitForConnection() {
|
|
||||||
if (::listen(this->serverSocketFileDescriptor.value(), 3) != 0) {
|
|
||||||
throw Exception{"Failed to listen on server socket"};
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto eventFileDescriptor = this->epollInstance.waitForEvent();
|
|
||||||
if (
|
|
||||||
!eventFileDescriptor.has_value()
|
|
||||||
|| *eventFileDescriptor == this->interruptEventNotifier.getFileDescriptor()
|
|
||||||
) {
|
|
||||||
this->interruptEventNotifier.clear();
|
|
||||||
throw DebugServerInterrupted{};
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
if (firstRawPacket.size() == 5 && firstRawPacket[1] == 0x03) {
|
|
||||||
// Interrupt packet that came in too quickly before another packet
|
|
||||||
debugSession->pendingInterrupt = true;
|
|
||||||
|
|
||||||
} 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() + 1, rawPacket.end()};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 (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("lr") == 0) {
|
|
||||||
return std::make_unique<CommandPackets::ListRegistersMonitor>(std::move(*(monitorCommand.release())));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monitorCommand->command.find("rr") == 0) {
|
|
||||||
return std::make_unique<CommandPackets::ReadRegistersMonitor>(std::move(*(monitorCommand.release())));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monitorCommand->command.find("wr") == 0) {
|
|
||||||
return std::make_unique<CommandPackets::WriteRegisterMonitor>(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_unique<CommandPacket>(rawPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (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&) {
|
|
||||||
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 stopped event - " + exception.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbRspDebugServer::handleTargetStoppedGdbResponse(Targets::TargetMemoryAddress programAddress) {
|
|
||||||
auto* debugSession = this->getActiveDebugSession();
|
|
||||||
|
|
||||||
if (debugSession->activeRangeSteppingSession.has_value()) {
|
|
||||||
debugSession->terminateRangeSteppingSession(this->targetControllerService);
|
|
||||||
}
|
|
||||||
|
|
||||||
debugSession->connection.writePacket(ResponsePackets::TargetStopped{Signal::TRAP});
|
|
||||||
debugSession->waitingForBreak = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GdbRspDebugServer::handleTargetResumedGdbResponse() {
|
|
||||||
auto* debugSession = this->getActiveDebugSession();
|
|
||||||
|
|
||||||
if (debugSession->waitingForBreak && debugSession->pendingInterrupt) {
|
|
||||||
Logger::info("Servicing pending interrupt");
|
|
||||||
this->targetControllerService.stopTargetExecution();
|
|
||||||
|
|
||||||
if (debugSession->activeRangeSteppingSession.has_value()) {
|
|
||||||
debugSession->terminateRangeSteppingSession(this->targetControllerService);
|
|
||||||
}
|
|
||||||
|
|
||||||
debugSession->connection.writePacket(ResponsePackets::TargetStopped{Signal::INTERRUPTED});
|
|
||||||
debugSession->pendingInterrupt = false;
|
|
||||||
debugSession->waitingForBreak = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,27 +5,71 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <variant>
|
||||||
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "src/DebugServer/ServerInterface.hpp"
|
#include "src/DebugServer/ServerInterface.hpp"
|
||||||
|
|
||||||
#include "GdbDebugServerConfig.hpp"
|
#include "GdbDebugServerConfig.hpp"
|
||||||
#include "src/EventManager/EventListener.hpp"
|
|
||||||
#include "src/Helpers/EpollInstance.hpp"
|
|
||||||
#include "src/Helpers/EventFdNotifier.hpp"
|
|
||||||
#include "src/Services/TargetControllerService.hpp"
|
|
||||||
#include "src/Targets/TargetDescriptor.hpp"
|
|
||||||
|
|
||||||
#include "Connection.hpp"
|
#include "Connection.hpp"
|
||||||
#include "TargetDescriptor.hpp"
|
#include "TargetDescriptor.hpp"
|
||||||
#include "DebugSession.hpp"
|
#include "DebugSession.hpp"
|
||||||
#include "Signal.hpp"
|
#include "Signal.hpp"
|
||||||
#include "RegisterDescriptor.hpp"
|
#include "RegisterDescriptor.hpp"
|
||||||
#include "Feature.hpp"
|
#include "Feature.hpp"
|
||||||
#include "CommandPackets/CommandPacket.hpp"
|
|
||||||
|
#include "src/EventManager/EventListener.hpp"
|
||||||
|
#include "src/Helpers/EpollInstance.hpp"
|
||||||
|
#include "src/Helpers/EventFdNotifier.hpp"
|
||||||
|
#include "src/Services/TargetControllerService.hpp"
|
||||||
|
#include "src/Targets/TargetDescriptor.hpp"
|
||||||
|
|
||||||
#include "src/EventManager/Events/TargetStateChanged.hpp"
|
#include "src/EventManager/Events/TargetStateChanged.hpp"
|
||||||
|
#include "src/EventManager/EventManager.hpp"
|
||||||
|
|
||||||
|
#include "src/Logger/Logger.hpp"
|
||||||
|
|
||||||
|
#include "Exceptions/ClientDisconnected.hpp"
|
||||||
|
#include "Exceptions/ClientNotSupported.hpp"
|
||||||
|
#include "Exceptions/ClientCommunicationError.hpp"
|
||||||
|
#include "Exceptions/DebugSessionInitialisationFailure.hpp"
|
||||||
|
#include "Exceptions/DebugServerInterrupted.hpp"
|
||||||
|
|
||||||
|
#include "src/Exceptions/Exception.hpp"
|
||||||
|
#include "src/Exceptions/InvalidConfig.hpp"
|
||||||
|
|
||||||
|
// Command packets
|
||||||
|
#include "CommandPackets/CommandPacket.hpp"
|
||||||
|
#include "CommandPackets/CommandPacket.hpp"
|
||||||
|
#include "CommandPackets/SupportedFeaturesQuery.hpp"
|
||||||
|
#include "CommandPackets/InterruptExecution.hpp"
|
||||||
|
#include "CommandPackets/ContinueExecution.hpp"
|
||||||
|
#include "CommandPackets/StepExecution.hpp"
|
||||||
|
#include "CommandPackets/SetBreakpoint.hpp"
|
||||||
|
#include "CommandPackets/RemoveBreakpoint.hpp"
|
||||||
|
#include "CommandPackets/Monitor.hpp"
|
||||||
|
#include "CommandPackets/ResetTarget.hpp"
|
||||||
|
#include "CommandPackets/HelpMonitorInfo.hpp"
|
||||||
|
#include "CommandPackets/BloomVersion.hpp"
|
||||||
|
#include "CommandPackets/BloomVersionMachine.hpp"
|
||||||
|
#include "CommandPackets/Detach.hpp"
|
||||||
|
#include "CommandPackets/ListRegistersMonitor.hpp"
|
||||||
|
#include "CommandPackets/ReadRegistersMonitor.hpp"
|
||||||
|
#include "CommandPackets/WriteRegisterMonitor.hpp"
|
||||||
|
|
||||||
|
#ifndef EXCLUDE_INSIGHT
|
||||||
|
#include "CommandPackets/ActivateInsight.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Response packets
|
||||||
|
#include "ResponsePackets/TargetStopped.hpp"
|
||||||
|
|
||||||
|
#include "src/Services/ProcessService.hpp"
|
||||||
|
#include "src/Services/StringService.hpp"
|
||||||
|
|
||||||
namespace DebugServer::Gdb
|
namespace DebugServer::Gdb
|
||||||
{
|
{
|
||||||
@@ -38,15 +82,30 @@ namespace DebugServer::Gdb
|
|||||||
* See https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html for more info on the GDB Remote Serial
|
* See https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html for more info on the GDB Remote Serial
|
||||||
* Protocol.
|
* Protocol.
|
||||||
*/
|
*/
|
||||||
|
template<
|
||||||
|
typename GdbTargetDescriptorType,
|
||||||
|
typename DebugSessionType,
|
||||||
|
typename CommandPacketType
|
||||||
|
>
|
||||||
|
requires
|
||||||
|
std::is_base_of_v<TargetDescriptor, GdbTargetDescriptorType>
|
||||||
|
&& std::is_base_of_v<DebugSession, DebugSessionType>
|
||||||
class GdbRspDebugServer: public ServerInterface
|
class GdbRspDebugServer: public ServerInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit GdbRspDebugServer(
|
explicit GdbRspDebugServer(
|
||||||
const DebugServerConfig& debugServerConfig,
|
const DebugServerConfig& debugServerConfig,
|
||||||
const Targets::TargetDescriptor& targetDescriptor,
|
const Targets::TargetDescriptor& targetDescriptor,
|
||||||
|
GdbTargetDescriptorType&& gdbTargetDescriptor,
|
||||||
EventListener& eventListener,
|
EventListener& eventListener,
|
||||||
EventFdNotifier& eventNotifier
|
EventFdNotifier& eventNotifier
|
||||||
);
|
)
|
||||||
|
: debugServerConfig(GdbDebugServerConfig{debugServerConfig})
|
||||||
|
, targetDescriptor(targetDescriptor)
|
||||||
|
, gdbTargetDescriptor(std::move(gdbTargetDescriptor))
|
||||||
|
, eventListener(eventListener)
|
||||||
|
, interruptEventNotifier(eventNotifier)
|
||||||
|
{};
|
||||||
|
|
||||||
GdbRspDebugServer() = delete;
|
GdbRspDebugServer() = delete;
|
||||||
virtual ~GdbRspDebugServer() = default;
|
virtual ~GdbRspDebugServer() = default;
|
||||||
@@ -59,30 +118,183 @@ namespace DebugServer::Gdb
|
|||||||
|
|
||||||
[[nodiscard]] std::string getName() const override {
|
[[nodiscard]] std::string getName() const override {
|
||||||
return "GDB Remote Serial Protocol DebugServer";
|
return "GDB Remote Serial Protocol DebugServer";
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares the GDB server for listing on the selected address and port.
|
* Prepares the GDB server for listing on the selected address and port.
|
||||||
*/
|
*/
|
||||||
void init() override;
|
void init() override {
|
||||||
|
this->socketAddress.sin_family = AF_INET;
|
||||||
|
this->socketAddress.sin_port = htons(this->debugServerConfig.listeningPortNumber);
|
||||||
|
|
||||||
|
if (
|
||||||
|
::inet_pton(
|
||||||
|
AF_INET,
|
||||||
|
this->debugServerConfig.listeningAddress.c_str(),
|
||||||
|
&(this->socketAddress.sin_addr)
|
||||||
|
) == 0
|
||||||
|
) {
|
||||||
|
// Invalid IP address
|
||||||
|
throw ::Exceptions::InvalidConfig{
|
||||||
|
"Invalid IP address provided in config file: (\"" + this->debugServerConfig.listeningAddress + "\")"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto socketFileDescriptor = int{0};
|
||||||
|
if ((socketFileDescriptor = ::socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
||||||
|
throw ::Exceptions::Exception{"Failed to create socket file descriptor."};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto enableReuseAddressSocketOption = int{1};
|
||||||
|
if (
|
||||||
|
::setsockopt(
|
||||||
|
socketFileDescriptor,
|
||||||
|
SOL_SOCKET,
|
||||||
|
SO_REUSEADDR,
|
||||||
|
&(enableReuseAddressSocketOption),
|
||||||
|
sizeof(enableReuseAddressSocketOption)
|
||||||
|
) < 0
|
||||||
|
) {
|
||||||
|
Logger::error("Failed to set socket SO_REUSEADDR option.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
::bind(
|
||||||
|
socketFileDescriptor,
|
||||||
|
reinterpret_cast<const sockaddr*>(&(this->socketAddress)),
|
||||||
|
sizeof(this->socketAddress)
|
||||||
|
) < 0
|
||||||
|
) {
|
||||||
|
throw ::Exceptions::Exception{
|
||||||
|
"Failed to bind address. The selected port number ("
|
||||||
|
+ std::to_string(this->debugServerConfig.listeningPortNumber) + ") may be in use."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
this->serverSocketFileDescriptor = socketFileDescriptor;
|
||||||
|
|
||||||
|
this->epollInstance.addEntry(
|
||||||
|
this->serverSocketFileDescriptor.value(),
|
||||||
|
static_cast<std::uint16_t>(::EPOLL_EVENTS::EPOLLIN)
|
||||||
|
);
|
||||||
|
|
||||||
|
this->epollInstance.addEntry(
|
||||||
|
this->interruptEventNotifier.getFileDescriptor(),
|
||||||
|
static_cast<std::uint16_t>(::EPOLL_EVENTS::EPOLLIN)
|
||||||
|
);
|
||||||
|
|
||||||
|
Logger::info("GDB RSP address: " + this->debugServerConfig.listeningAddress);
|
||||||
|
Logger::info("GDB RSP port: " + std::to_string(this->debugServerConfig.listeningPortNumber));
|
||||||
|
|
||||||
|
this->eventListener.template registerCallbackForEventType<Events::TargetStateChanged>(
|
||||||
|
std::bind(&GdbRspDebugServer::onTargetStateChanged, this, std::placeholders::_1)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (Services::ProcessService::isManagedByClion()) {
|
||||||
|
Logger::warning(
|
||||||
|
"Bloom's process is being managed by CLion - Bloom will automatically shutdown upon detaching from GDB."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminates any active debug session and closes the listening socket.
|
* Terminates any active debug session and closes the listening socket.
|
||||||
*/
|
*/
|
||||||
void close() override;
|
void close() override {
|
||||||
|
this->endDebugSession();
|
||||||
|
|
||||||
|
if (this->serverSocketFileDescriptor.has_value()) {
|
||||||
|
::close(this->serverSocketFileDescriptor.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for a connection from a GDB client or services an active one.
|
* Waits for a connection from a GDB client or services an active one.
|
||||||
*
|
*
|
||||||
* This function will return when any blocking operation is interrupted via this->interruptEventNotifier.
|
* This function will return when any blocking operation is interrupted via this->interruptEventNotifier.
|
||||||
*/
|
*/
|
||||||
void run() override;
|
void run() override {
|
||||||
|
try {
|
||||||
|
if (!this->debugSession.has_value()) {
|
||||||
|
Logger::info("Waiting for GDB RSP connection");
|
||||||
|
|
||||||
|
auto connection = this->waitForConnection();
|
||||||
|
Logger::info("Accepted GDP RSP connection from " + connection.getIpAddress());
|
||||||
|
|
||||||
|
this->debugSession.emplace(
|
||||||
|
std::move(connection),
|
||||||
|
this->getSupportedFeatures(),
|
||||||
|
this->debugServerConfig
|
||||||
|
);
|
||||||
|
|
||||||
|
this->targetControllerService.stopTargetExecution();
|
||||||
|
this->targetControllerService.resetTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto commandPacketVariant = this->waitForCommandPacket();
|
||||||
|
|
||||||
|
if (std::holds_alternative<std::unique_ptr<CommandPacketType>>(commandPacketVariant)) {
|
||||||
|
const auto& commandPacket = std::get<std::unique_ptr<CommandPacketType>>(commandPacketVariant);
|
||||||
|
if (!commandPacket) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
commandPacket->handle(
|
||||||
|
*(this->debugSession),
|
||||||
|
this->gdbTargetDescriptor,
|
||||||
|
this->targetDescriptor,
|
||||||
|
this->targetControllerService
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const auto& commandPacket = std::get<std::unique_ptr<CommandPackets::CommandPacket>>(
|
||||||
|
commandPacketVariant
|
||||||
|
);
|
||||||
|
if (!commandPacket) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
commandPacket->handle(
|
||||||
|
*(this->debugSession),
|
||||||
|
this->gdbTargetDescriptor,
|
||||||
|
this->targetDescriptor,
|
||||||
|
this->targetControllerService
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (const Exceptions::ClientDisconnected&) {
|
||||||
|
Logger::info("GDB RSP client disconnected");
|
||||||
|
this->endDebugSession();
|
||||||
|
return;
|
||||||
|
|
||||||
|
} catch (const Exceptions::ClientCommunicationError& exception) {
|
||||||
|
Logger::error(
|
||||||
|
"GDB RSP client communication error - " + exception.getMessage() + " - closing connection"
|
||||||
|
);
|
||||||
|
this->endDebugSession();
|
||||||
|
return;
|
||||||
|
|
||||||
|
} catch (const Exceptions::ClientNotSupported& exception) {
|
||||||
|
Logger::error("Invalid GDB RSP client - " + exception.getMessage() + " - closing connection");
|
||||||
|
this->endDebugSession();
|
||||||
|
return;
|
||||||
|
|
||||||
|
} catch (const Exceptions::DebugSessionInitialisationFailure& exception) {
|
||||||
|
Logger::warning("GDB debug session initialisation failure - " + exception.getMessage());
|
||||||
|
this->endDebugSession();
|
||||||
|
return;
|
||||||
|
|
||||||
|
} catch (const Exceptions::DebugServerInterrupted&) {
|
||||||
|
// Server was interrupted by an event
|
||||||
|
Logger::debug("GDB RSP interrupted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GdbDebugServerConfig debugServerConfig;
|
GdbDebugServerConfig debugServerConfig;
|
||||||
|
|
||||||
const Targets::TargetDescriptor& targetDescriptor;
|
const Targets::TargetDescriptor& targetDescriptor;
|
||||||
|
GdbTargetDescriptorType gdbTargetDescriptor;
|
||||||
EventListener& eventListener;
|
EventListener& eventListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,88 +317,255 @@ namespace DebugServer::Gdb
|
|||||||
* See EpollInstance
|
* See EpollInstance
|
||||||
* See EventFdNotifier
|
* See EventFdNotifier
|
||||||
*/
|
*/
|
||||||
EpollInstance epollInstance = EpollInstance();
|
EpollInstance epollInstance = {};
|
||||||
|
|
||||||
/**
|
Services::TargetControllerService targetControllerService = {};
|
||||||
* Passed to command handlers (see CommandPacket::handle()).
|
|
||||||
*
|
|
||||||
* See documentation in src/DebugServer/Gdb/README.md for more on how GDB commands are processed.
|
|
||||||
*/
|
|
||||||
Services::TargetControllerService targetControllerService = Services::TargetControllerService();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listening socket address
|
|
||||||
*/
|
|
||||||
struct sockaddr_in socketAddress = {};
|
struct sockaddr_in socketAddress = {};
|
||||||
|
|
||||||
/**
|
|
||||||
* Listening socket file descriptor
|
|
||||||
*/
|
|
||||||
std::optional<int> serverSocketFileDescriptor;
|
std::optional<int> serverSocketFileDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should start a new debug session for the newly established `connection`.
|
* The active debug session.
|
||||||
*
|
|
||||||
* @param connection
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
virtual DebugSession* startDebugSession(Connection&& connection) = 0;
|
std::optional<DebugSessionType> debugSession;
|
||||||
|
|
||||||
/**
|
void endDebugSession() {
|
||||||
* Should end the currently active debug session, if one exists.
|
this->debugSession.reset();
|
||||||
*/
|
}
|
||||||
virtual void endDebugSession() = 0;
|
|
||||||
|
|
||||||
/**
|
Connection waitForConnection() {
|
||||||
* Should return a non-owning pointer of the currently active debug session. Or nullptr if there is no active
|
if (::listen(this->serverSocketFileDescriptor.value(), 3) != 0) {
|
||||||
* session.
|
throw ::Exceptions::Exception{"Failed to listen on server socket"};
|
||||||
*
|
}
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
virtual DebugSession* getActiveDebugSession() = 0;
|
|
||||||
|
|
||||||
/**
|
const auto eventFileDescriptor = this->epollInstance.waitForEvent();
|
||||||
* Waits for a GDB client to connect on the listening socket.
|
if (
|
||||||
*/
|
!eventFileDescriptor.has_value()
|
||||||
Connection waitForConnection();
|
|| *eventFileDescriptor == this->interruptEventNotifier.getFileDescriptor()
|
||||||
|
) {
|
||||||
|
this->interruptEventNotifier.clear();
|
||||||
|
throw Exceptions::DebugServerInterrupted{};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {this->serverSocketFileDescriptor.value(), this->interruptEventNotifier};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for a command packet from the connected GDB client.
|
* Waits for a command packet from the connected GDB client.
|
||||||
*
|
*
|
||||||
|
* This function will first attempt to construct a server-implementation-specific command packet, but if that
|
||||||
|
* yields nothing, it will fall back to a generic command packet.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<CommandPackets::CommandPacket> waitForCommandPacket();
|
std::variant<
|
||||||
|
std::unique_ptr<CommandPacketType>,
|
||||||
|
std::unique_ptr<CommandPackets::CommandPacket>
|
||||||
|
> waitForCommandPacket() {
|
||||||
|
const auto rawPackets = this->debugSession->connection.readRawPackets();
|
||||||
|
assert(!rawPackets.empty());
|
||||||
|
|
||||||
|
if (rawPackets.size() > 1) {
|
||||||
|
const auto& firstRawPacket = rawPackets.front();
|
||||||
|
|
||||||
|
if (firstRawPacket.size() == 5 && firstRawPacket[1] == 0x03) {
|
||||||
|
// Interrupt packet that came in too quickly before another packet
|
||||||
|
this->debugSession->pendingInterrupt = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Logger::warning("Multiple packets received from GDB - only the most recent will be processed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto commandPacket = this->rawPacketToCommandPacket(rawPackets.back());
|
||||||
|
if (commandPacket) {
|
||||||
|
return commandPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->rawPacketToGenericCommandPacket(rawPackets.back());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should construct a derived instance of the CommandPackets::CommandPacket class, from a raw packet.
|
* Should construct a server-implementation-specific command packet from a raw packet.
|
||||||
*
|
*
|
||||||
* Derived implementations of this GDB server class can override this function to include support for more
|
* This function should return a nullptr if the server implementation does not recognise/handle the command.
|
||||||
* specific GDB commands. For example, the AVR GDB implementation overrides this function to support AVR
|
|
||||||
* specific implementations of the read and write memory GDB commands.
|
|
||||||
*
|
|
||||||
* This function should never return a nullptr. If the command is unknown, it should simply return an
|
|
||||||
* instance of the CommandPackets::CommandPacket base class. The handler (CommandPacket::handle()) for the base
|
|
||||||
* class will handle unknown packets by responding with an empty response packet (as is expected by the GDB
|
|
||||||
* client).
|
|
||||||
*
|
*
|
||||||
* @param rawPacket
|
* @param rawPacket
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
virtual std::unique_ptr<CommandPackets::CommandPacket> resolveCommandPacket(const RawPacket& rawPacket);
|
virtual std::unique_ptr<CommandPacketType> rawPacketToCommandPacket(const RawPacket& rawPacket) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should return the GDB target descriptor for the connected target.
|
* If rawPacketToCommandPacket() returns a nullptr, we'll attempt to construct a generic command packet.
|
||||||
*
|
*
|
||||||
* NOTE: This function returns a target descriptor specific to GDB and the target. It's not the same data
|
* @param rawPacket
|
||||||
* struct as Targets::TargetDescriptor. But the GDB target descriptor does hold an instance to
|
* @return
|
||||||
* Targets::TargetDescriptor. See the Gdb::TargetDescriptor::targetDescriptor class member.
|
*/
|
||||||
|
std::unique_ptr<CommandPackets::CommandPacket> rawPacketToGenericCommandPacket(const RawPacket& rawPacket) {
|
||||||
|
if (rawPacket.size() < 2) {
|
||||||
|
throw ::Exceptions::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() + 1, rawPacket.end()};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 (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("lr") == 0) {
|
||||||
|
return std::make_unique<CommandPackets::ListRegistersMonitor>(std::move(*(monitorCommand.release())));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitorCommand->command.find("rr") == 0) {
|
||||||
|
return std::make_unique<CommandPackets::ReadRegistersMonitor>(std::move(*(monitorCommand.release())));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitorCommand->command.find("wr") == 0) {
|
||||||
|
return std::make_unique<CommandPackets::WriteRegisterMonitor>(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<CommandPackets::CommandPacket>(rawPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should return a set of GDB features supported by the AVR GDB server. Each supported feature may come with an
|
||||||
|
* optional value.
|
||||||
|
*
|
||||||
|
* The set of features returned by this function will be stored against the active debug session object.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
virtual const TargetDescriptor& getGdbTargetDescriptor() = 0;
|
virtual std::set<std::pair<Feature, std::optional<std::string>>> getSupportedFeatures() = 0;
|
||||||
|
|
||||||
void onTargetStateChanged(const Events::TargetStateChanged& event);
|
void onTargetStateChanged(const Events::TargetStateChanged& event) {
|
||||||
virtual void handleTargetStoppedGdbResponse(Targets::TargetMemoryAddress programAddress);
|
using Targets::TargetExecutionState;
|
||||||
virtual void handleTargetResumedGdbResponse();
|
|
||||||
|
if (!this->debugSession.has_value()) {
|
||||||
|
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 (executionState == TargetExecutionState::STOPPED && this->debugSession->waitingForBreak) {
|
||||||
|
this->handleTargetStoppedGdbResponse(event.newState.programCounter.load().value());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
executionState == TargetExecutionState::RUNNING
|
||||||
|
|| executionState == TargetExecutionState::STEPPING
|
||||||
|
) {
|
||||||
|
this->handleTargetResumedGdbResponse();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (const Exceptions::ClientDisconnected&) {
|
||||||
|
Logger::info("GDB RSP client disconnected");
|
||||||
|
this->endDebugSession();
|
||||||
|
return;
|
||||||
|
|
||||||
|
} catch (const Exceptions::ClientCommunicationError& exception) {
|
||||||
|
Logger::error(
|
||||||
|
"GDB RSP client communication error - " + exception.getMessage() + " - closing connection"
|
||||||
|
);
|
||||||
|
this->endDebugSession();
|
||||||
|
return;
|
||||||
|
|
||||||
|
} catch (const Exceptions::DebugServerInterrupted&) {
|
||||||
|
// Server was interrupted
|
||||||
|
Logger::debug("GDB RSP interrupted");
|
||||||
|
return;
|
||||||
|
|
||||||
|
} catch (const ::Exceptions::Exception& exception) {
|
||||||
|
Logger::error("Failed to handle target execution stopped event - " + exception.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void handleTargetStoppedGdbResponse(Targets::TargetMemoryAddress programAddress) {
|
||||||
|
if (this->debugSession->activeRangeSteppingSession.has_value()) {
|
||||||
|
this->debugSession->terminateRangeSteppingSession(this->targetControllerService);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->debugSession->connection.writePacket(ResponsePackets::TargetStopped{Signal::TRAP});
|
||||||
|
this->debugSession->waitingForBreak = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void handleTargetResumedGdbResponse() {
|
||||||
|
if (this->debugSession->waitingForBreak && this->debugSession->pendingInterrupt) {
|
||||||
|
Logger::info("Servicing pending interrupt");
|
||||||
|
this->targetControllerService.stopTargetExecution();
|
||||||
|
|
||||||
|
if (this->debugSession->activeRangeSteppingSession.has_value()) {
|
||||||
|
this->debugSession->terminateRangeSteppingSession(this->targetControllerService);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->debugSession->connection.writePacket(ResponsePackets::TargetStopped{Signal::INTERRUPTED});
|
||||||
|
this->debugSession->pendingInterrupt = false;
|
||||||
|
this->debugSession->waitingForBreak = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user