Give memchecks/breakpoints a consistent interface.

Removes the limit on max breakpoints, and makes everything use accessors
for both that look roughly the same.
This commit is contained in:
Unknown W. Brackets 2013-06-30 15:16:58 -07:00
parent 6ce949a743
commit 6bd4383a8a
4 changed files with 280 additions and 164 deletions

View File

@ -23,12 +23,9 @@
#include "../MIPS/JitCommon/JitCommon.h"
#include <cstdio>
#define MAX_BREAKPOINTS 16
static FixedSizeUnorderedSet<BreakPoint, MAX_BREAKPOINTS> m_iBreakPoints;
std::vector<MemCheck> CBreakPoints::MemChecks;
std::vector<BreakPoint> CBreakPoints::breakPoints_;
u32 CBreakPoints::breakSkipFirstAt_ = 0;
std::vector<MemCheck> CBreakPoints::memChecks_;
MemCheck::MemCheck(void)
{
@ -37,13 +34,14 @@ MemCheck::MemCheck(void)
void MemCheck::Action(u32 addr, bool write, int size, u32 pc)
{
if ((write && bOnWrite) || (!write && bOnRead))
int mask = write ? MEMCHECK_WRITE : MEMCHECK_READ;
if (cond & mask)
{
++numHits;
if (bLog)
if (result & MEMCHECK_LOG)
NOTICE_LOG(MEMMAP, "CHK %s%i at %08x (%s), PC=%08x (%s)", write ? "Write" : "Read", size * 8, addr, symbolMap.GetDescription(addr), pc, symbolMap.GetDescription(pc));
if (bBreak)
if (result & MEMCHECK_BREAK)
{
Core_EnableStepping(true);
host->SetDebugMode(true);
@ -51,76 +49,180 @@ void MemCheck::Action(u32 addr, bool write, int size, u32 pc)
}
}
bool CBreakPoints::IsAddressBreakPoint(u32 _iAddress)
size_t CBreakPoints::FindBreakpoint(u32 addr, bool matchTemp, bool temp)
{
for (size_t i = 0; i < m_iBreakPoints.size(); i++)
if (m_iBreakPoints[i].iAddress == _iAddress)
return true;
return false;
}
bool CBreakPoints::IsTempBreakPoint(u32 _iAddress)
{
for (size_t i = 0; i < m_iBreakPoints.size(); i++)
if (m_iBreakPoints[i].iAddress == _iAddress && m_iBreakPoints[i].bTemporary)
return true;
return false;
}
void CBreakPoints::RemoveBreakPoint(u32 _iAddress)
{
for (size_t i = 0; i < m_iBreakPoints.size(); i++)
for (size_t i = 0; i < breakPoints_.size(); ++i)
{
if (m_iBreakPoints[i].iAddress == _iAddress)
{
m_iBreakPoints.remove(m_iBreakPoints[i]);
InvalidateJit(_iAddress);
host->UpdateDisassembly(); // redraw in order to not show the breakpoint anymore
break;
}
if (breakPoints_[i].iAddress == addr && (!matchTemp || breakPoints_[i].bTemporary == temp))
return i;
}
return INVALID_BREAKPOINT;
}
size_t CBreakPoints::FindMemCheck(u32 start, u32 end)
{
for (size_t i = 0; i < memChecks_.size(); ++i)
{
if (memChecks_[i].start == start && memChecks_[i].end == end)
return i;
}
return INVALID_MEMCHECK;
}
bool CBreakPoints::IsAddressBreakPoint(u32 addr)
{
size_t bp = FindBreakpoint(addr);
return bp != INVALID_BREAKPOINT && breakPoints_[bp].bOn;
}
bool CBreakPoints::IsTempBreakPoint(u32 addr)
{
size_t bp = FindBreakpoint(addr, true, true);
return bp != INVALID_BREAKPOINT;
}
void CBreakPoints::AddBreakPoint(u32 addr, bool temp)
{
size_t bp = FindBreakpoint(addr, true, temp);
if (bp == INVALID_BREAKPOINT)
{
BreakPoint pt;
pt.bOn = true;
pt.bTemporary = temp;
pt.iAddress = addr;
breakPoints_.push_back(pt);
Update(addr);
}
else if (!breakPoints_[bp].bOn)
{
breakPoints_[bp].bOn = true;
Update(addr);
}
}
void CBreakPoints::RemoveBreakPoint(u32 addr)
{
size_t bp = FindBreakpoint(addr);
if (bp != INVALID_BREAKPOINT)
{
breakPoints_.erase(breakPoints_.begin() + bp);
// Check again, there might've been an overlapping temp breakpoint.
bp = FindBreakpoint(addr);
if (bp != INVALID_BREAKPOINT)
breakPoints_.erase(breakPoints_.begin() + bp);
Update(addr);
}
}
void CBreakPoints::ChangeBreakPoint(u32 addr, bool status)
{
size_t bp = FindBreakpoint(addr);
if (bp != INVALID_BREAKPOINT)
{
breakPoints_[bp].bOn = status;
Update(addr);
}
}
void CBreakPoints::ClearAllBreakPoints()
{
m_iBreakPoints.clear();
InvalidateJit();
if (!breakPoints_.empty())
{
breakPoints_.clear();
Update();
}
}
void CBreakPoints::ClearTemporaryBreakPoints()
{
if (m_iBreakPoints.size() == 0) return;
if (breakPoints_.empty())
return;
bool update = false;
for (int i = (int)m_iBreakPoints.size()-1; i >= 0; --i)
for (int i = (int)breakPoints_.size()-1; i >= 0; --i)
{
if (m_iBreakPoints[i].bTemporary)
if (breakPoints_[i].bTemporary)
{
InvalidateJit(m_iBreakPoints[i].iAddress);
m_iBreakPoints.remove(m_iBreakPoints[i]);
breakPoints_.erase(breakPoints_.begin() + i);
update = true;
}
}
if (update) host->UpdateDisassembly(); // redraw in order to not show the breakpoint anymore
if (update)
Update();
}
void CBreakPoints::AddMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result)
{
size_t mc = FindMemCheck(start, end);
if (mc == INVALID_MEMCHECK)
{
MemCheck check;
check.start = start;
check.end = end;
check.cond = cond;
check.result = result;
memChecks_.push_back(check);
Update();
}
else
{
memChecks_[mc].cond = (MemCheckCondition)(memChecks_[mc].cond | cond);
memChecks_[mc].result = (MemCheckResult)(memChecks_[mc].result | result);
Update();
}
}
void CBreakPoints::RemoveMemCheck(u32 start, u32 end)
{
size_t mc = FindMemCheck(start, end);
if (mc != INVALID_MEMCHECK)
{
memChecks_.erase(memChecks_.begin() + mc);
Update();
}
}
void CBreakPoints::ChangeMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result)
{
size_t mc = FindMemCheck(start, end);
if (mc != INVALID_MEMCHECK)
{
memChecks_[mc].cond = cond;
memChecks_[mc].result = result;
Update();
}
}
void CBreakPoints::ClearAllMemChecks()
{
if (!memChecks_.empty())
{
memChecks_.clear();
Update();
}
}
MemCheck *CBreakPoints::GetMemCheck(u32 address, int size)
{
std::vector<MemCheck>::iterator iter;
for (iter = MemChecks.begin(); iter != MemChecks.end(); ++iter)
for (iter = memChecks_.begin(); iter != memChecks_.end(); ++iter)
{
MemCheck &check = *iter;
if (check.bRange)
if (check.end != 0)
{
if (address >= check.iStartAddress && address + size < check.iEndAddress)
if (address >= check.start && address + size < check.end)
return &check;
}
else
{
if (check.iStartAddress==address)
if (check.start==address)
return &check;
}
}
@ -129,46 +231,41 @@ MemCheck *CBreakPoints::GetMemCheck(u32 address, int size)
return 0;
}
void CBreakPoints::AddBreakPoint(u32 _iAddress, bool temp)
{
if (!IsAddressBreakPoint(_iAddress))
{
BreakPoint pt;
pt.bOn=true;
pt.bTemporary=temp;
pt.iAddress = _iAddress;
m_iBreakPoints.insert(pt);
InvalidateJit(_iAddress);
host->UpdateDisassembly(); // redraw in order to show the breakpoint
}
}
void CBreakPoints::InvalidateJit(u32 _iAddress)
{
// Don't want to clear cache while running, I think?
if (MIPSComp::jit && Core_IsInactive())
MIPSComp::jit->ClearCacheAt(_iAddress);
}
void CBreakPoints::InvalidateJit()
{
// Don't want to clear cache while running, I think?
if (MIPSComp::jit && Core_IsInactive())
MIPSComp::jit->ClearCache();
}
int CBreakPoints::GetNumBreakpoints()
{
return (int)m_iBreakPoints.size();
return (int)breakPoints_.size();
}
BreakPoint CBreakPoints::GetBreakpoint(int i)
const BreakPoint CBreakPoints::GetBreakpoint(int i)
{
return m_iBreakPoints[i];
return breakPoints_[i];
}
int CBreakPoints::GetBreakpointAddress(int i)
{
return m_iBreakPoints[i].iAddress;
return breakPoints_[i].iAddress;
}
const std::vector<MemCheck> CBreakPoints::GetMemChecks()
{
return memChecks_;
}
const std::vector<BreakPoint> CBreakPoints::GetBreakpoints()
{
return breakPoints_;
}
void CBreakPoints::Update(u32 addr)
{
if (MIPSComp::jit && Core_IsInactive())
{
if (addr != 0)
MIPSComp::jit->ClearCacheAt(addr);
else
MIPSComp::jit->ClearCache();
}
// Redraw in order to show the breakpoint.
host->UpdateDisassembly();
}

View File

@ -17,8 +17,8 @@
#pragma once
#include "../../Globals.h"
#include <vector>
struct BreakPoint
{
@ -26,72 +26,94 @@ struct BreakPoint
bool bOn;
bool bTemporary;
bool operator == (const BreakPoint &other) const {
return iAddress == other.iAddress && bOn == other.bOn && bTemporary == other.bTemporary;
bool operator == (const BreakPoint &other) const {
return iAddress == other.iAddress;
}
bool operator < (const BreakPoint &other) const {
return iAddress < other.iAddress;
}
};
enum MemCheckCondition
{
MEMCHECK_READ = 0x01,
MEMCHECK_WRITE = 0x02,
MEMCHECK_READWRITE = 0x03,
};
enum MemCheckResult
{
MEMCHECK_IGNORE = 0x00,
MEMCHECK_LOG = 0x01,
MEMCHECK_BREAK = 0x02,
MEMCHECK_BOTH = 0x03,
};
struct MemCheck
{
MemCheck();
u32 iStartAddress;
u32 iEndAddress;
u32 start;
u32 end;
bool bRange;
bool bOnRead;
bool bOnWrite;
bool bLog;
bool bBreak;
MemCheckCondition cond;
MemCheckResult result;
u32 numHits;
void Action(u32 addr, bool write, int size, u32 pc);
bool operator == (const MemCheck &other) const {
return start == other.start && end == other.end;
}
};
// BreakPoints cannot overlap, only one is allowed per address.
// MemChecks can overlap, as long as their ends are different.
// WARNING: MemChecks are not used in the interpreter or HLE currently.
class CBreakPoints
{
private:
enum { MAX_NUMBER_OF_CALLSTACK_ENTRIES = 16384};
enum { MAX_NUMBER_OF_BREAKPOINTS = 16};
static u32 breakSkipFirstAt_;
public:
// WARNING: Not used in interpreter or HLE, only jit CPU memory access.
static std::vector<MemCheck> MemChecks;
// is address breakpoint
static bool IsAddressBreakPoint(u32 _iAddress);
// WARNING: Not used in interpreter or HLE, only jit CPU memory access.
static MemCheck *GetMemCheck(u32 address, int size);
// is break on count
static bool IsBreakOnCount(u32 _iAddress);
static bool IsTempBreakPoint(u32 _iAddress);
// AddBreakPoint
static void AddBreakPoint(u32 _iAddress, bool temp=false);
// Remove Breakpoint
static void RemoveBreakPoint(u32 _iAddress);
static const size_t INVALID_BREAKPOINT = -1;
static const size_t INVALID_MEMCHECK = -1;
static bool IsAddressBreakPoint(u32 addr);
static bool IsTempBreakPoint(u32 addr);
static void AddBreakPoint(u32 addr, bool temp = false);
static void RemoveBreakPoint(u32 addr);
static void ChangeBreakPoint(u32 addr, bool enable);
static void ClearAllBreakPoints();
static void ClearTemporaryBreakPoints();
static void InvalidateJit(u32 _iAddress);
static void InvalidateJit();
static void AddMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
static void RemoveMemCheck(u32 start, u32 end);
static void ChangeMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
static void ClearAllMemChecks();
static MemCheck *GetMemCheck(u32 address, int size);
static int GetNumBreakpoints();
static BreakPoint GetBreakpoint(int i);
static const BreakPoint GetBreakpoint(int i);
static int GetBreakpointAddress(int i);
// TODO: MemChecks somehow too?
static void SetSkipFirst(u32 pc) { breakSkipFirstAt_ = pc; }
static u32 CheckSkipFirst() { u32 pc = breakSkipFirstAt_; breakSkipFirstAt_ = 0; return pc; }
static const std::vector<MemCheck> GetMemChecks();
static const std::vector<BreakPoint> GetBreakpoints();
static void Update(u32 addr = 0);
private:
static size_t FindBreakpoint(u32 addr, bool matchTemp = false, bool temp = false);
// Finds exactly, not using a range check.
static size_t FindMemCheck(u32 start, u32 end);
static std::vector<BreakPoint> breakPoints_;
static u32 breakSkipFirstAt_;
static std::vector<MemCheck> memChecks_;
};

View File

@ -469,7 +469,7 @@ Jit::JitSafeMem::JitSafeMem(Jit *jit, int raddr, s32 offset)
: jit_(jit), raddr_(raddr), offset_(offset), needsCheck_(false), needsSkip_(false)
{
// This makes it more instructions, so let's play it safe and say we need a far jump.
far_ = !g_Config.bIgnoreBadMemAccess || !CBreakPoints::MemChecks.empty();
far_ = !g_Config.bIgnoreBadMemAccess || !CBreakPoints::GetMemChecks().empty();
if (jit_->gpr.IsImmediate(raddr_))
iaddr_ = jit_->gpr.GetImmediate32(raddr_) + offset_;
else
@ -714,9 +714,9 @@ void Jit::JitSafeMem::MemCheckImm(ReadType type)
MemCheck *check = CBreakPoints::GetMemCheck(iaddr_, size_);
if (check)
{
if (!check->bOnRead && type == MEM_READ)
if (!(check->cond & MEMCHECK_READ) && type == MEM_READ)
return;
if (!check->bOnWrite && type == MEM_WRITE)
if (!(check->cond & MEMCHECK_WRITE) && type == MEM_WRITE)
return;
jit_->MOV(32, M(&jit_->mips_->pc), Imm32(jit_->js.compilerPC));
@ -730,24 +730,25 @@ void Jit::JitSafeMem::MemCheckImm(ReadType type)
void Jit::JitSafeMem::MemCheckAsm(ReadType type)
{
for (auto it = CBreakPoints::MemChecks.begin(), end = CBreakPoints::MemChecks.end(); it != end; ++it)
auto memchecks = CBreakPoints::GetMemChecks();
for (auto it = memchecks.begin(), end = memchecks.end(); it != end; ++it)
{
if (!it->bOnRead && type == MEM_READ)
continue;
if (!it->bOnWrite && type == MEM_WRITE)
continue;
if (!(it->cond & MEMCHECK_READ) && type == MEM_READ)
return;
if (!(it->cond & MEMCHECK_WRITE) && type == MEM_WRITE)
return;
FixupBranch skipNext, skipNextRange;
if (it->bRange)
if (it->end != 0)
{
jit_->CMP(32, R(xaddr_), Imm32(it->iStartAddress - offset_));
jit_->CMP(32, R(xaddr_), Imm32(it->start - offset_));
skipNext = jit_->J_CC(CC_B);
jit_->CMP(32, R(xaddr_), Imm32(it->iEndAddress - offset_ - size_));
jit_->CMP(32, R(xaddr_), Imm32(it->end - offset_ - size_));
skipNextRange = jit_->J_CC(CC_AE);
}
else
{
jit_->CMP(32, R(xaddr_), Imm32(it->iStartAddress - offset_));
jit_->CMP(32, R(xaddr_), Imm32(it->start - offset_));
skipNext = jit_->J_CC(CC_NE);
}
@ -762,7 +763,7 @@ void Jit::JitSafeMem::MemCheckAsm(ReadType type)
jit_->js.afterOp = JitState::AFTER_CORE_STATE | JitState::AFTER_REWIND_PC_BAD_STATE;
jit_->SetJumpTarget(skipNext);
if (it->bRange)
if (it->end != 0)
jit_->SetJumpTarget(skipNextRange);
}
}

View File

@ -213,8 +213,8 @@ CDisasm::~CDisasm()
int getTotalBreakpointCount()
{
int count = (int)CBreakPoints::MemChecks.size();
for (int i = 0; i < CBreakPoints::GetNumBreakpoints(); i++)
int count = (int)CBreakPoints::GetMemChecks().size();
for (size_t i = 0; i < CBreakPoints::GetBreakpoints().size(); i++)
{
if (!CBreakPoints::GetBreakpoint(i).bTemporary) count++;
}
@ -255,13 +255,13 @@ void CDisasm::updateBreakpointList()
int getBreakpointIndex(int itemIndex, bool& isMemory)
{
// memory breakpoints first
if (itemIndex < CBreakPoints::MemChecks.size())
if (itemIndex < CBreakPoints::GetMemChecks().size())
{
isMemory = true;
return itemIndex;
}
itemIndex -= (int)CBreakPoints::MemChecks.size();
itemIndex -= (int)CBreakPoints::GetMemChecks().size();
int i = 0;
while (i < CBreakPoints::GetNumBreakpoints())
@ -294,9 +294,8 @@ void CDisasm::removeBreakpoint(int itemIndex)
if (isMemory)
{
CBreakPoints::MemChecks.erase(CBreakPoints::MemChecks.begin()+index);
CBreakPoints::InvalidateJit();
updateBreakpointList();
auto memchecks = CBreakPoints::GetMemChecks();
CBreakPoints::RemoveMemCheck(memchecks[index].start, memchecks[index].end);
} else {
u32 address = CBreakPoints::GetBreakpointAddress(index);
CBreakPoints::RemoveBreakPoint(address);
@ -311,7 +310,8 @@ void CDisasm::gotoBreakpointAddress(int itemIndex)
if (isMemory)
{
u32 address = CBreakPoints::MemChecks[index].iStartAddress;
auto memchecks = CBreakPoints::GetMemChecks();
u32 address = memchecks[index].start;
for (int i=0; i<numCPUs; i++)
if (memoryWindow[i])
@ -337,7 +337,7 @@ void CDisasm::handleBreakpointNotify(LPARAM lParam)
if (((LPNMHDR)lParam)->code == LVN_GETDISPINFO)
{
NMLVDISPINFO* dispInfo = (NMLVDISPINFO*)lParam;
std::vector<MemCheck>& mem = CBreakPoints::MemChecks;
auto mem = CBreakPoints::GetMemChecks();
bool isMemory;
int index = getBreakpointIndex(dispInfo->item.iItem,isMemory);
@ -350,12 +350,18 @@ void CDisasm::handleBreakpointNotify(LPARAM lParam)
{
if (isMemory)
{
if (mem[index].bOnRead)
switch (mem[index].cond)
{
strcpy(breakpointText,"Read");
if (mem[index].bOnWrite) strcat(breakpointText,"/");
case MEMCHECK_READ:
strcpy(breakpointText, "Read");
break;
case MEMCHECK_WRITE:
strcpy(breakpointText, "Write");
break;
case MEMCHECK_READWRITE:
strcpy(breakpointText, "Read/Write");
break;
}
if (mem[index].bOnWrite) strcat(breakpointText,"Write");
} else {
strcpy(breakpointText,"Execute");
}
@ -365,7 +371,7 @@ void CDisasm::handleBreakpointNotify(LPARAM lParam)
{
if (isMemory)
{
sprintf(breakpointText,"0x%08X",mem[index].iStartAddress);
sprintf(breakpointText,"0x%08X",mem[index].start);
} else {
sprintf(breakpointText,"0x%08X",CBreakPoints::GetBreakpointAddress(index));
}
@ -375,8 +381,8 @@ void CDisasm::handleBreakpointNotify(LPARAM lParam)
{
if (isMemory)
{
if (mem[index].bRange == false) sprintf(breakpointText,"0x%08X",1);
else sprintf(breakpointText,"0x%08X",mem[index].iEndAddress-mem[index].iStartAddress);
if (mem[index].end == 0) sprintf(breakpointText,"0x%08X",1);
else sprintf(breakpointText,"0x%08X",mem[index].end-mem[index].start);
} else {
const char* sym = cpu->findSymbolForAddress(CBreakPoints::GetBreakpointAddress(index));
if (sym != NULL)
@ -413,7 +419,7 @@ void CDisasm::handleBreakpointNotify(LPARAM lParam)
{
if (isMemory)
{
strcpy(breakpointText,mem[index].bBreak == true ? "True" : "False");
strcpy(breakpointText,mem[index].result & MEMCHECK_BREAK ? "True" : "False");
} else {
strcpy(breakpointText,CBreakPoints::GetBreakpoint(index).bOn ? "True" : "False");
}
@ -647,19 +653,9 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam)
Core_WaitInactive(200);
}
MemCheck check;
if (executeExpressionWindow(m_hDlg,cpu,check.iStartAddress))
{
check.bBreak = true;
check.bLog = true;
check.bOnRead = true;
check.bOnWrite = true;
check.bRange = false;
CBreakPoints::MemChecks.push_back(check);
CBreakPoints::InvalidateJit();
updateBreakpointList();
}
u32 start;
if (executeExpressionWindow(m_hDlg,cpu,start))
CBreakPoints::AddMemCheck(start, 0, MEMCHECK_READWRITE, MEMCHECK_BOTH);
if (isRunning)
{