Skip to content

Commit

Permalink
Added support for RAM breakpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
sysprogs committed Sep 2, 2012
1 parent a701800 commit 685c047
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 44 deletions.
158 changes: 132 additions & 26 deletions MSP430EEMTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ enum MSP430_MSG
WMX_STOPPED,
};

bool MSP430Proxy::MSP430EEMTarget::Initialize( const char *pPortName )
bool MSP430Proxy::MSP430EEMTarget::Initialize(const GlobalSettings &settings)
{
if (!__super::Initialize(pPortName))
if (!__super::Initialize(settings))
return false;

if (m_pBreakpointManager)
Expand All @@ -46,7 +46,7 @@ bool MSP430Proxy::MSP430EEMTarget::Initialize( const char *pPortName )
memset(&bkpt, 0, sizeof(bkpt));

bkpt.bpMode = BP_COMPLEX;
bkpt.lAddrVal = m_BreakpointInstruction;
bkpt.lAddrVal = settings.BreakpointInstruction;
bkpt.bpType = BP_MDB;
bkpt.bpAccess = BP_FETCH;
bkpt.bpAction = BP_BRK;
Expand All @@ -56,7 +56,7 @@ bool MSP430Proxy::MSP430EEMTarget::Initialize( const char *pPortName )
if (MSP430_EEM_SetBreakpoint(&m_SoftwareBreakpointWrapperHandle, &bkpt) != STATUS_OK)
REPORT_AND_RETURN("Cannot create a MDB breakpoint for handling software breakpoints", false);

m_pBreakpointManager = new SoftwareBreakpointManager(m_DeviceInfo.mainStart, m_DeviceInfo.mainEnd, m_BreakpointInstruction);
m_pBreakpointManager = new SoftwareBreakpointManager(m_DeviceInfo.mainStart, m_DeviceInfo.mainEnd, settings.BreakpointInstruction, settings.InstantBreakpointCleanup);

return true;
}
Expand Down Expand Up @@ -100,12 +100,18 @@ bool MSP430Proxy::MSP430EEMTarget::WaitForJTAGEvent()
{
m_TargetStopped.Wait();

bool breakIn = m_BreakInPending;
m_BreakInPending = false;

LONG regPC = 0;

if (MSP430_Read_Register(&regPC, PC) != STATUS_OK)
REPORT_AND_RETURN("Cannot read PC register", false);

SoftwareBreakpointManager::BreakpointState bpState = m_pBreakpointManager->GetBreakpointState(regPC - 2);
if (m_RAMBreakpoints.IsBreakpointPresent((USHORT)regPC - 2))
bpState = SoftwareBreakpointManager::BreakpointActive;

switch(bpState)
{
case SoftwareBreakpointManager::BreakpointActive:
Expand All @@ -128,7 +134,7 @@ bool MSP430Proxy::MSP430EEMTarget::WaitForJTAGEvent()
if (MSP430_Write_Register(&regPC, PC) != STATUS_OK)
REPORT_AND_RETURN("Cannot read PC register", false);

if (bpState == SoftwareBreakpointManager::BreakpointInactive && m_LastResumeMode != SINGLE_STEP)
if (bpState == SoftwareBreakpointManager::BreakpointInactive && m_LastResumeMode != SINGLE_STEP && !breakIn)
{
//Skip the breakpoint
if (!DoResumeTarget(m_LastResumeMode))
Expand All @@ -151,19 +157,15 @@ GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::CreateBreakpoint( B
switch(type)
{
case bptSoftwareBreakpoint:
if (!m_pBreakpointManager->SetBreakpoint((unsigned)Address))
return kGDBUnknownError;
return kGDBSuccess;
return DoCreateCodeBreakpoint(false, Address, pCookie);
case bptHardwareBreakpoint:
bkpt.bpMode = BP_CODE;
bkpt.lAddrVal = (LONG)Address;
bkpt.bpCondition = BP_NO_COND;
bkpt.bpAction = BP_BRK;
break;
return DoCreateCodeBreakpoint(true, Address, pCookie);
default:
return kGDBNotSupported;
}

//TODO: support memory breakpoints

WORD bpHandle = 0;
if (MSP430_EEM_SetBreakpoint(&bpHandle, &bkpt) != STATUS_OK)
REPORT_AND_RETURN("Cannot set an EEM breakpoint", kGDBUnknownError);
Expand All @@ -175,22 +177,16 @@ GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::CreateBreakpoint( B

GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::RemoveBreakpoint( BreakpointType type, ULONGLONG Address, INT_PTR Cookie )
{
if (type == bptSoftwareBreakpoint)
switch(type)
{
if (!m_pBreakpointManager->RemoveBreakpoint((unsigned)Address))
return kGDBUnknownError;
return kGDBSuccess;
case bptSoftwareBreakpoint:
return DoRemoveCodeBreakpoint(false, Address, Cookie);
case bptHardwareBreakpoint:
return DoRemoveCodeBreakpoint(true, Address, Cookie);
default:
return kGDBNotSupported;
}

BpParameter_t bkpt;
memset(&bkpt, 0, sizeof(bkpt));
bkpt.bpMode = BP_CLEAR;

WORD bpHandle = (WORD)Cookie;

if (MSP430_EEM_SetBreakpoint(&bpHandle, &bkpt) != STATUS_OK)
REPORT_AND_RETURN("Cannot remove an EEM breakpoint", kGDBUnknownError);

return kGDBSuccess;
}

Expand Down Expand Up @@ -222,6 +218,7 @@ bool MSP430Proxy::MSP430EEMTarget::DoResumeTarget( RUN_MODES_t mode )
GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::SendBreakInRequestAsync()
{
LONG state;
m_BreakInPending = true;
if (MSP430_State(&state, TRUE, NULL) != STATUS_OK)
REPORT_AND_RETURN("Cannot stop device", kGDBNotSupported);
return kGDBSuccess;
Expand All @@ -248,3 +245,112 @@ GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::WriteTargetMemory(

return kGDBSuccess;
}

//Breakpoint cookie format:
//32 bits: [type : 4] [reserved : 12] [user_data : 16]
//For RAM breakpoints user_data contains the original insn
//For hardware breakpoints user_data contains the handle returned by EEM API

enum {kBpCookieTypeMask = 0xF0000000,
kBpCookieTypeHardware = 0x10000000,
kBpCookieTypeSoftwareFLASH = 0x20000000,
kBpCookieTypeSoftwareRAM = 0x30000000,
kBpCookieDataMask = 0x0000FFFF};

#define MAKE_BP_COOKIE(type, data) (((type) & kBpCookieTypeMask) | ((data) & kBpCookieDataMask))

GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::DoCreateCodeBreakpoint( bool hardware, ULONGLONG Address, INT_PTR *pCookie )
{
if (hardware)
{
BpParameter_t bkpt;
memset(&bkpt, 0, sizeof(bkpt));
bkpt.bpMode = BP_CODE;
bkpt.lAddrVal = (LONG)Address;
bkpt.bpCondition = BP_NO_COND;
bkpt.bpAction = BP_BRK;

WORD bpHandle = 0;
if (MSP430_EEM_SetBreakpoint(&bpHandle, &bkpt) != STATUS_OK)
REPORT_AND_RETURN("Cannot set an EEM breakpoint", kGDBUnknownError);

C_ASSERT(sizeof(bpHandle) == 2);
*pCookie = MAKE_BP_COOKIE(kBpCookieTypeHardware, bpHandle);

return kGDBSuccess;
}
else
{
if (!IsFLASHAddress(Address))
{
ULONG addr = (ULONG)(Address & ~1);

if (m_RAMBreakpoints.IsBreakpointPresent((USHORT)addr))
{
printf("Cannot set a breakpoint at 0x%04x. Breakpoint already exists.\n", (unsigned)Address);
return kGDBUnknownError;
}

unsigned short insn;
if (MSP430_Read_Memory(addr, (char *)&insn, 2) != STATUS_OK)
REPORT_AND_RETURN("Cannot set a software breakpoint in RAM", kGDBUnknownError);

*pCookie = MAKE_BP_COOKIE(kBpCookieTypeSoftwareRAM, insn);

insn = m_BreakpointInstruction;
if (MSP430_Write_Memory(addr, (char *)&insn, 2) != STATUS_OK)
REPORT_AND_RETURN("Cannot set a software breakpoint in RAM", kGDBUnknownError);

m_RAMBreakpoints.InsertBreakpoint((USHORT)addr);
}
else
{
if (!m_pBreakpointManager->SetBreakpoint((unsigned)Address))
return kGDBUnknownError;
*pCookie = MAKE_BP_COOKIE(kBpCookieTypeSoftwareFLASH, 0);
}
return kGDBSuccess;
}
}

GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::DoRemoveCodeBreakpoint( bool hardware, ULONGLONG Address, INT_PTR Cookie )
{
if (hardware)
{
ASSERT((Cookie & kBpCookieTypeMask) == kBpCookieTypeHardware);
BpParameter_t bkpt;
memset(&bkpt, 0, sizeof(bkpt));
bkpt.bpMode = BP_CLEAR;

WORD bpHandle = (WORD)(Cookie & kBpCookieDataMask);

if (MSP430_EEM_SetBreakpoint(&bpHandle, &bkpt) != STATUS_OK)
REPORT_AND_RETURN("Cannot remove an EEM breakpoint", kGDBUnknownError);
return kGDBSuccess;
}
else
{
if ((Cookie & kBpCookieTypeMask) == kBpCookieTypeHardware)
return DoRemoveCodeBreakpoint(true, Address, Cookie);

if (!IsFLASHAddress(Address))
{
ASSERT((Cookie & kBpCookieTypeMask) == kBpCookieTypeSoftwareRAM);
unsigned short originalINSN = (unsigned short)(Cookie & kBpCookieDataMask);

if (MSP430_Write_Memory(Address & ~1, (char *)&originalINSN, 2) != STATUS_OK)
REPORT_AND_RETURN("Cannot remove a software breakpoint from RAM", kGDBUnknownError);

m_RAMBreakpoints.RemoveBreakpoint((USHORT)(Address & ~1));
}
else
{
ASSERT((Cookie & kBpCookieTypeMask) == kBpCookieTypeSoftwareFLASH);
if (!m_pBreakpointManager->RemoveBreakpoint((unsigned)Address))
return kGDBUnknownError;
}

return kGDBSuccess;
}

}
49 changes: 44 additions & 5 deletions MSP430EEMTarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "MSP430Target.h"
#include <bzscore/sync.h>
#include <set>

namespace MSP430Proxy
{
Expand All @@ -17,29 +18,64 @@ namespace MSP430Proxy

WORD m_SoftwareBreakpointWrapperHandle;
SoftwareBreakpointManager *m_pBreakpointManager;
unsigned short m_BreakpointInstruction;
RUN_MODES_t m_LastResumeMode;

//! If the last resume operation was resuming from a breakpoint, this field contains its address. If not, it contains -1
LONG m_BreakpointAddrOfLastResumeOp;

private:
class RAMBreakpointDatabase
{
private:
unsigned char Flags[65536 / 8];

public:
RAMBreakpointDatabase()
{
memset(Flags, 0, sizeof(Flags));
}

void InsertBreakpoint(USHORT addr)
{
Flags[addr >> 3] |= (1 << (addr & 7));
}

void RemoveBreakpoint(USHORT addr)
{
Flags[addr >> 3] &= ~(1 << (addr & 7));
}

bool IsBreakpointPresent(USHORT addr)
{
return (Flags[addr >> 3] & (1 << (addr & 7))) != 0;
}
};

RAMBreakpointDatabase m_RAMBreakpoints;
unsigned short m_BreakpointInstruction;

protected:
virtual bool DoResumeTarget(RUN_MODES_t mode) override;

bool IsFLASHAddress(ULONGLONG addr)
{
return addr >= m_DeviceInfo.mainStart && addr <= m_DeviceInfo.mainEnd;
}

public:
MSP430EEMTarget(unsigned short breakpointInstruction = 0x4343)
MSP430EEMTarget()
: m_bEEMInitialized(false)
, m_SoftwareBreakpointWrapperHandle(0)
, m_pBreakpointManager(NULL)
, m_BreakpointInstruction(breakpointInstruction)
, m_LastResumeMode(RUN_TO_BREAKPOINT)
, m_BreakpointAddrOfLastResumeOp(-1)
, m_BreakpointInstruction(0) //Will be updated in Initialize()
{
}


public:
virtual bool Initialize(const char *pPortName) override;
virtual bool Initialize(const GlobalSettings &settings) override;
~MSP430EEMTarget();

virtual bool WaitForJTAGEvent() override;
Expand All @@ -48,6 +84,9 @@ namespace MSP430Proxy
static void sEEMHandler(UINT MsgId, UINT wParam, LONG lParam, LONG clientHandle);
void EEMNotificationHandler(MSP430_MSG wMsg, WPARAM wParam, LPARAM lParam);

GDBStatus DoCreateCodeBreakpoint(bool hardware, ULONGLONG Address, INT_PTR *pCookie);
GDBStatus DoRemoveCodeBreakpoint(bool hardware, ULONGLONG Address, INT_PTR Cookie);

public:
virtual GDBStatus CreateBreakpoint(BreakpointType type, ULONGLONG Address, unsigned kind, OUT INT_PTR *pCookie) override;
virtual GDBStatus RemoveBreakpoint(BreakpointType type, ULONGLONG Address, INT_PTR Cookie) override;
Expand Down
11 changes: 7 additions & 4 deletions MSP430Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ using namespace MSP430Proxy;
#define REPORT_AND_RETURN(msg, result) { ReportLastMSP430Error(msg); return result; }
#define MAIN_SEGMENT_SIZE 512

bool MSP430Proxy::MSP430GDBTarget::Initialize( const char *pPortName )
bool MSP430Proxy::MSP430GDBTarget::Initialize(const GlobalSettings &settings)
{
if (m_bClosePending)
return m_bValid;

LONG version = 0;
if (MSP430_Initialize((char *)pPortName, &version) != STATUS_OK)
if (MSP430_Initialize((char *)settings.PortName, &version) != STATUS_OK)
REPORT_AND_RETURN("Cannot initialize MSP430.DLL", false);
m_bClosePending = true;

if (MSP430_VCC(3333) != STATUS_OK)
if (MSP430_VCC(settings.Voltage) != STATUS_OK)
REPORT_AND_RETURN("Cannot enable Vcc", false);

if (MSP430_Identify((char *)&m_DeviceInfo, sizeof(m_DeviceInfo), DEVICE_UNKNOWN) != STATUS_OK)
Expand All @@ -27,6 +27,9 @@ bool MSP430Proxy::MSP430GDBTarget::Initialize( const char *pPortName )
if (MSP430_Reset(ALL_RESETS, FALSE, FALSE) != STATUS_OK)
REPORT_AND_RETURN("Cannot reset the MSP430 device", false);

m_DeviceInfo.string[__countof(m_DeviceInfo.string) - 1] = 0;
printf("Found an %s device with %d hardware breakpoints.\n", m_DeviceInfo.string, m_DeviceInfo.nBreakpoints);

m_UsedBreakpoints.resize(m_DeviceInfo.nBreakpoints);

m_bValid = true;
Expand Down Expand Up @@ -168,7 +171,7 @@ GDBServerFoundation::GDBStatus MSP430GDBTarget::WriteTargetRegisters( int thread
if (registers[i].Valid)
{
mask |= MASKREG(i);
rawRegs[i] = registers[i].ToUInt32() & 0xFFFF;
rawRegs[i] = registers[i].ToUInt16();
}

if (MSP430_Write_Registers(rawRegs, mask) != STATUS_OK)
Expand Down
7 changes: 5 additions & 2 deletions MSP430Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "registers-msp430.h"
#include <vector>
#include "settings.h"

enum MSP430_MSG;

Expand All @@ -22,9 +23,11 @@ namespace MSP430Proxy
bool m_bClosePending, m_bValid;
std::vector<bool> m_UsedBreakpoints;

bool m_BreakInPending;
bool m_bFLASHErased;

protected:
bool m_BreakInPending;

protected:
virtual bool WaitForJTAGEvent();
void ReportLastMSP430Error(const char *pHint);
Expand All @@ -41,7 +44,7 @@ namespace MSP430Proxy

~MSP430GDBTarget();

virtual bool Initialize(const char *pPortName);
virtual bool Initialize(const GlobalSettings &settings);

virtual GDBStatus GetLastStopRecord(TargetStopRecord *pRec);
virtual GDBStatus ResumeAndWait(int threadID);
Expand Down
Loading

0 comments on commit 685c047

Please sign in to comment.