Files
BloomPatched/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.cpp

224 lines
8.9 KiB
C++
Raw Normal View History

#include "AvrGdbRsp.hpp"
#include "src/Services/StringService.hpp"
// Command packets
#include "CommandPackets/ReadRegister.hpp"
#include "CommandPackets/ReadRegisters.hpp"
#include "CommandPackets/WriteRegister.hpp"
#include "CommandPackets/ReadMemory.hpp"
#include "CommandPackets/WriteMemory.hpp"
#include "CommandPackets/ReadMemoryMap.hpp"
#include "CommandPackets/FlashErase.hpp"
#include "CommandPackets/FlashWrite.hpp"
#include "CommandPackets/FlashDone.hpp"
#include "CommandPackets/VContSupportedActionsQuery.hpp"
#include "CommandPackets/VContContinueExecution.hpp"
#include "CommandPackets/VContStepExecution.hpp"
#include "CommandPackets/VContRangeStep.hpp"
namespace DebugServer::Gdb::AvrGdb
{
using namespace Exceptions;
using Targets::TargetRegisterDescriptor;
using Targets::TargetRegisterType;
AvrGdbRsp::AvrGdbRsp(
const DebugServerConfig& debugServerConfig,
EventListener& eventListener,
EventFdNotifier& eventNotifier
)
: GdbRspDebugServer(debugServerConfig, eventListener, eventNotifier)
, gdbTargetDescriptor(TargetDescriptor(this->targetControllerService.getTargetDescriptor()))
{}
DebugSession* AvrGdbRsp::startDebugSession(Connection&& connection) {
this->activeDebugSession.emplace(
std::move(connection),
this->getSupportedFeatures(),
this->gdbTargetDescriptor,
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(
2022-10-01 21:01:37 +01:00
const RawPacket& rawPacket
) {
using AvrGdb::CommandPackets::ReadRegister;
using AvrGdb::CommandPackets::ReadRegisters;
using AvrGdb::CommandPackets::WriteRegister;
using AvrGdb::CommandPackets::ReadMemory;
using AvrGdb::CommandPackets::WriteMemory;
using AvrGdb::CommandPackets::ReadMemoryMap;
using AvrGdb::CommandPackets::FlashErase;
using AvrGdb::CommandPackets::FlashWrite;
using AvrGdb::CommandPackets::FlashDone;
using AvrGdb::CommandPackets::VContSupportedActionsQuery;
using AvrGdb::CommandPackets::VContContinueExecution;
using AvrGdb::CommandPackets::VContStepExecution;
using AvrGdb::CommandPackets::VContRangeStep;
if (rawPacket.size() >= 2) {
if (rawPacket[1] == 'p') {
return std::make_unique<ReadRegister>(rawPacket);
}
if (rawPacket[1] == 'g') {
return std::make_unique<ReadRegisters>(rawPacket);
}
if (rawPacket[1] == 'P') {
return std::make_unique<WriteRegister>(rawPacket);
}
if (rawPacket[1] == 'm') {
return std::make_unique<ReadMemory>(rawPacket, this->gdbTargetDescriptor);
}
if (rawPacket[1] == 'M') {
return std::make_unique<WriteMemory>(rawPacket, this->gdbTargetDescriptor);
}
const auto rawPacketString = std::string(rawPacket.begin() + 1, rawPacket.end());
if (rawPacketString.find("qXfer:memory-map:read::") == 0) {
return std::make_unique<ReadMemoryMap>(rawPacket);
}
if (rawPacketString.find("vFlashErase") == 0) {
return std::make_unique<FlashErase>(rawPacket);
}
if (rawPacketString.find("vFlashWrite") == 0) {
return std::make_unique<FlashWrite>(rawPacket);
}
if (rawPacketString.find("vFlashDone") == 0) {
return std::make_unique<FlashDone>(rawPacket);
}
if (rawPacketString.find("vCont?") == 0) {
return std::make_unique<VContSupportedActionsQuery>(rawPacket);
}
if (rawPacketString.find("vCont;c") == 0 || rawPacketString.find("vCont;C") == 0) {
return std::make_unique<VContContinueExecution>(rawPacket);
}
if (rawPacketString.find("vCont;s") == 0 || rawPacketString.find("vCont;S") == 0) {
return std::make_unique<VContStepExecution>(rawPacket);
}
if (this->debugServerConfig.rangeStepping) {
if (rawPacketString.find("vCont;r") == 0) {
return std::make_unique<VContRangeStep>(rawPacket);
}
}
}
return GdbRspDebugServer::resolveCommandPacket(rawPacket);
}
std::set<std::pair<Feature, std::optional<std::string>>> AvrGdbRsp::getSupportedFeatures() {
return {
{Feature::SOFTWARE_BREAKPOINTS, std::nullopt},
{Feature::MEMORY_MAP_READ, std::nullopt},
{Feature::VCONT_ACTIONS_QUERY, std::nullopt},
};
}
void AvrGdbRsp::handleTargetStoppedGdbResponse(Targets::TargetMemoryAddress programAddress) {
using Services::StringService;
Logger::debug("Target stopped at byte address: 0x" + StringService::toHex(programAddress));
auto& activeRangeSteppingSession = this->activeDebugSession->activeRangeSteppingSession;
if (
activeRangeSteppingSession.has_value()
&& programAddress >= activeRangeSteppingSession->range.startAddress
&& programAddress < activeRangeSteppingSession->range.endAddress
) {
/*
* The target stopped within the stepping range of an active range stepping session.
*
* We need to figure out why, and determine whether the stop should be reported to GDB.
*/
2023-09-20 23:37:54 +01:00
if (this->activeDebugSession->externalBreakpointsByAddress.contains(programAddress)) {
/*
* The target stopped due to an external breakpoint, set by GDB.
*
* We have to end the range stepping session and report this to GDB.
*/
Logger::debug("Reached external breakpoint within stepping range");
this->activeDebugSession->terminateRangeSteppingSession(this->targetControllerService);
return GdbRspDebugServer::handleTargetStoppedGdbResponse(programAddress);
}
if (activeRangeSteppingSession->interceptedAddresses.contains(programAddress)) {
/*
* The target stopped due to an intercepting breakpoint, but we're still within the stepping range,
* which can only mean that we weren't sure where this instruction would lead to.
*
* We must perform a single step and see what happens. If the instruction takes us out of the stepping
* range, we'll end the session and report back to GDB.
*/
Logger::debug("Reached intercepting breakpoint within stepping range");
Logger::debug("Attempting single step from 0x" + StringService::toHex(programAddress));
activeRangeSteppingSession->singleStepping = true;
this->targetControllerService.stepTargetExecution(std::nullopt);
return;
}
if (activeRangeSteppingSession->singleStepping) {
/*
* We performed a single step once and we're still within the stepping range, so we're good to
* continue the range stepping session.
*/
Logger::debug("Completed single step - PC still within stepping range");
Logger::debug("Continuing range stepping");
activeRangeSteppingSession->singleStepping = false;
this->targetControllerService.continueTargetExecution(
std::nullopt,
activeRangeSteppingSession->range.endAddress
);
return;
}
/*
* If we get here, the target stopped for an unknown reason that doesn't seem to have anything to do with
* the active range stepping session.
*
* This could be due to a permanent breakpoint in the target's program code.
*
* 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");
this->activeDebugSession->terminateRangeSteppingSession(this->targetControllerService);
return GdbRspDebugServer::handleTargetStoppedGdbResponse(programAddress);
}
// Report the stop to GDB
return GdbRspDebugServer::handleTargetStoppedGdbResponse(programAddress);
}
}