Support for hardware breakpoints

This commit is contained in:
Nav
2023-09-20 23:37:54 +01:00
parent df5a141089
commit d7b59cac59
24 changed files with 480 additions and 68 deletions

View File

@@ -0,0 +1,30 @@
#pragma once
#include <cstdint>
#include <utility>
#include "Avr8GenericCommandFrame.hpp"
namespace DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class ClearHardwareBreakpoint: public Avr8GenericCommandFrame<std::array<unsigned char, 3>>
{
public:
explicit ClearHardwareBreakpoint(std::uint8_t number)
: Avr8GenericCommandFrame()
{
/*
* The clear hardware breakpoint command consists of 3 bytes:
*
* 1. Command ID (0x41)
* 2. Version (0x00)
* 3. Breakpoint Number (1, 2, or 3)
*/
this->payload = {
0x41,
0x00,
number
};
}
};
}

View File

@@ -0,0 +1,40 @@
#pragma once
#include <cstdint>
#include <utility>
#include "Avr8GenericCommandFrame.hpp"
namespace DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class SetHardwareBreakpoint: public Avr8GenericCommandFrame<std::array<unsigned char, 9>>
{
public:
explicit SetHardwareBreakpoint(std::uint32_t address, std::uint8_t number)
: Avr8GenericCommandFrame()
{
/*
* The set hardware breakpoint command consists of 9 bytes:
*
* 1. Command ID (0x40)
* 2. Version (0x00)
* 3. Breakpoint Type (0x01 for program break)
* 4. Breakpoint Number (1, 2, or 3)
* 5. Program address (4 bytes) - the EDBG Protocol document states that this should be the word address,
* but that seems to be incorrect. The tool expects a byte address here.
* 5. Mode (0x03 for program break)
*/
this->payload = {
0x40,
0x00,
0x01,
number,
static_cast<unsigned char>(address),
static_cast<unsigned char>(address >> 8),
static_cast<unsigned char>(address >> 16),
static_cast<unsigned char>(address >> 24),
0x03
};
}
};
}

View File

@@ -34,6 +34,8 @@
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetSoftwareBreakpoints.hpp"
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ClearAllSoftwareBreakpoints.hpp"
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ClearSoftwareBreakpoints.hpp"
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetHardwareBreakpoint.hpp"
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ClearHardwareBreakpoint.hpp"
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/EnterProgrammingMode.hpp"
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/LeaveProgrammingMode.hpp"
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/EraseMemory.hpp"
@@ -58,6 +60,8 @@ namespace DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
using CommandFrames::Avr8Generic::SetSoftwareBreakpoints;
using CommandFrames::Avr8Generic::ClearSoftwareBreakpoints;
using CommandFrames::Avr8Generic::ClearAllSoftwareBreakpoints;
using CommandFrames::Avr8Generic::SetHardwareBreakpoint;
using CommandFrames::Avr8Generic::ClearHardwareBreakpoint;
using CommandFrames::Avr8Generic::ReadMemory;
using CommandFrames::Avr8Generic::EnterProgrammingMode;
using CommandFrames::Avr8Generic::LeaveProgrammingMode;
@@ -346,7 +350,7 @@ namespace DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
return responseFrame.extractSignature(this->targetConfig.physicalInterface);
}
void EdbgAvr8Interface::setBreakpoint(TargetMemoryAddress address) {
void EdbgAvr8Interface::setSoftwareBreakpoint(TargetMemoryAddress address) {
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
SetSoftwareBreakpoints({address})
);
@@ -356,7 +360,7 @@ namespace DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
}
}
void EdbgAvr8Interface::clearBreakpoint(TargetMemoryAddress address) {
void EdbgAvr8Interface::clearSoftwareBreakpoint(TargetMemoryAddress address) {
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
ClearSoftwareBreakpoints({address})
);
@@ -366,6 +370,55 @@ namespace DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
}
}
void EdbgAvr8Interface::setHardwareBreakpoint(TargetMemoryAddress address) {
static const auto getAvailableBreakpointNumbers = [this] () {
auto breakpointNumbers = std::set<std::uint8_t>({1, 2, 3});
for (const auto& [address, allocatedNumber] : this->hardwareBreakpointNumbersByAddress) {
breakpointNumbers.erase(allocatedNumber);
}
return breakpointNumbers;
};
const auto availableBreakpointNumbers = getAvailableBreakpointNumbers();
if (availableBreakpointNumbers.empty()) {
throw Exception("Maximum hardware breakpoints have been allocated");
}
const auto breakpointNumber = *(availableBreakpointNumbers.begin());
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
SetHardwareBreakpoint(address, breakpointNumber)
);
if (responseFrame.id == Avr8ResponseId::FAILED) {
throw Avr8CommandFailure("AVR8 Set hardware breakpoint command failed", responseFrame);
}
this->hardwareBreakpointNumbersByAddress.insert(std::pair(address, breakpointNumber));
}
void EdbgAvr8Interface::clearHardwareBreakpoint(TargetMemoryAddress address) {
const auto breakpointNumberIt = this->hardwareBreakpointNumbersByAddress.find(address);
if (breakpointNumberIt == this->hardwareBreakpointNumbersByAddress.end()) {
Logger::error("No hardware breakpoint at byte address 0x" + Services::StringService::toHex(address));
return;
}
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
ClearHardwareBreakpoint(breakpointNumberIt->second)
);
if (responseFrame.id == Avr8ResponseId::FAILED) {
throw Avr8CommandFailure("AVR8 Clear hardware breakpoint command failed", responseFrame);
}
this->hardwareBreakpointNumbersByAddress.erase(address);
}
void EdbgAvr8Interface::clearAllBreakpoints() {
const auto responseFrame = this->edbgInterface->sendAvrCommandFrameAndWaitForResponseFrame(
ClearAllSoftwareBreakpoints()

View File

@@ -164,18 +164,36 @@ namespace DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
* byte address.
*
* @param address
* The byte address to position the breakpoint.
* The byte address to place the breakpoint.
*/
void setBreakpoint(Targets::TargetMemoryAddress address) override;
void setSoftwareBreakpoint(Targets::TargetMemoryAddress address) override;
/**
* Issues the "Software Breakpoint Clear" command to the debug tool, clearing any breakpoint at the given
* byte address.
* Issues the "Software Breakpoint Clear" command to the debug tool, clearing any software breakpoint at the
* given byte address.
*
* @param address
* The byte address of the breakpoint to clear.
*/
void clearBreakpoint(Targets::TargetMemoryAddress address) override;
void clearSoftwareBreakpoint(Targets::TargetMemoryAddress address) override;
/**
* Issues the "Hardware Breakpoint Set" command to the debug tool, setting a hardware breakpoint at the given
* byte address.
*
* @param address
* The byte address to place the breakpoint.
*/
void setHardwareBreakpoint(Targets::TargetMemoryAddress address) override;
/**
* Issues the "Hardware Breakpoint Clear" command to the debug tool, clearing any hardware breakpoint at the
* given byte address.
*
* @param address
* The byte address of the breakpoint to clear.
*/
void clearHardwareBreakpoint(Targets::TargetMemoryAddress address) override;
/**
* Issues the "Software Breakpoint Clear All" command to the debug tool, clearing all software breakpoints
@@ -345,6 +363,12 @@ namespace DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
bool programmingModeEnabled = false;
/**
* Every hardware breakpoint is assigned a "breakpoint number", which we need to keep track of in order to
* clear a hardware breakpoint.
*/
std::map<Targets::TargetMemoryAddress, std::uint8_t> hardwareBreakpointNumbersByAddress;
/**
* Sends the necessary target parameters to the debug tool.
*

View File

@@ -100,14 +100,28 @@ namespace DebugToolDrivers::TargetInterfaces::Microchip::Avr::Avr8
*
* @param address
*/
virtual void setBreakpoint(Targets::TargetMemoryAddress address) = 0;
virtual void setSoftwareBreakpoint(Targets::TargetMemoryAddress address) = 0;
/**
* Should remove a software breakpoint at a given address.
*
* @param address
*/
virtual void clearBreakpoint(Targets::TargetMemoryAddress address) = 0;
virtual void clearSoftwareBreakpoint(Targets::TargetMemoryAddress address) = 0;
/**
* Should set a hardware breakpoint at a given address.
*
* @param address
*/
virtual void setHardwareBreakpoint(Targets::TargetMemoryAddress address) = 0;
/**
* Should remove a hardware breakpoint at a given address.
*
* @param address
*/
virtual void clearHardwareBreakpoint(Targets::TargetMemoryAddress address) = 0;
/**
* Should remove all software and hardware breakpoints on the target.