Support for hardware breakpoints
This commit is contained in:
@@ -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
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user