Debugger: Fixed issue that caused forbid breakpoints to prevent "run 1 frame/scanline/etc" from working properly in some scenarios

This commit is contained in:
Sour 2024-10-30 21:25:35 +09:00
parent f675ced226
commit ecd012c2fe
4 changed files with 69 additions and 29 deletions

View file

@ -302,17 +302,19 @@ enum class BreakSource
CpuStep,
PpuStep,
Irq,
Nmi,
//Used by DebugBreakHelper, prevents debugger getting focus
InternalOperation,
//Everything after InternalOperation is treated as an "Exception"
//Forbid breakpoints can block these, but not the other types above
BreakOnBrk,
BreakOnCop,
BreakOnWdm,
BreakOnStp,
BreakOnUninitMemoryRead,
Irq,
Nmi,
GbInvalidOamAccess,
GbInvalidVramAccess,
@ -363,6 +365,14 @@ enum class StepType
StepBack
};
enum class BreakType
{
None = 0,
User = 1,
Exception = 2,
Both = 3
};
struct StepRequest
{
int64_t BreakAddress = -1;
@ -374,8 +384,9 @@ struct StepRequest
bool HasRequest = false;
bool BreakNeeded = false;
BreakType BreakNeeded = BreakType::None;
BreakSource Source = BreakSource::Unspecified;
BreakSource ExSource = BreakSource::Unspecified;
StepRequest()
{
@ -397,27 +408,61 @@ struct StepRequest
HasRequest = (StepCount != -1 || PpuStepCount != -1 || BreakAddress != -1 || BreakScanline != INT32_MIN || CpuCycleStepCount != -1);
}
__forceinline void SetBreakSource(BreakSource source)
void ClearException()
{
if(Source == BreakSource::Unspecified) {
Source = source;
ExSource = BreakSource::Unspecified;
ClearBreakType(BreakType::Exception);
}
__forceinline void SetBreakSource(BreakSource source, bool breakNeeded)
{
if(source > BreakSource::InternalOperation) {
if(ExSource == BreakSource::Unspecified) {
ExSource = source;
}
if(breakNeeded) {
SetBreakType(BreakType::Exception);
}
} else {
if(Source == BreakSource::Unspecified) {
Source = source;
}
if(breakNeeded) {
SetBreakType(BreakType::User);
}
}
}
BreakSource GetBreakSource()
{
if(ExSource != BreakSource::Unspecified) {
return ExSource;
}
if(Source == BreakSource::Unspecified) {
if(BreakScanline != INT32_MIN || PpuStepCount >= 0) {
return BreakSource::PpuStep;
}
}
return Source;
}
__forceinline void SetBreakType(BreakType type)
{
BreakNeeded = (BreakType)((int)BreakNeeded | (int)type);
}
__forceinline void ClearBreakType(BreakType type)
{
BreakNeeded = (BreakType)((int)BreakNeeded & ~(int)type);
}
__forceinline void Break(BreakSource src)
{
BreakNeeded = true;
SetBreakSource(src);
SetBreakSource(src, true);
}
__forceinline void ProcessCpuExec()
@ -425,8 +470,7 @@ struct StepRequest
if(StepCount > 0) {
StepCount--;
if(StepCount == 0) {
BreakNeeded = true;
SetBreakSource(BreakSource::CpuStep);
SetBreakSource(BreakSource::CpuStep, true);
}
}
}
@ -436,8 +480,7 @@ struct StepRequest
if(CpuCycleStepCount > 0) {
CpuCycleStepCount--;
if(CpuCycleStepCount == 0) {
BreakNeeded = true;
SetBreakSource(BreakSource::CpuStep);
SetBreakSource(BreakSource::CpuStep, true);
return true;
}
}
@ -448,13 +491,11 @@ struct StepRequest
{
if(forNmi) {
if(Type == StepType::RunToNmi) {
BreakNeeded = true;
SetBreakSource(BreakSource::Nmi);
SetBreakSource(BreakSource::Nmi, true);
}
} else {
if(Type == StepType::RunToIrq) {
BreakNeeded = true;
SetBreakSource(BreakSource::Irq);
SetBreakSource(BreakSource::Irq, true);
}
}
}

View file

@ -368,7 +368,7 @@ void Debugger::ProcessHaltedCpu()
//Process cpu step requests as if each call to ProcessHaltedCpu is an instruction
StepRequest* req = dbg->GetStepRequest();
req->ProcessCpuExec();
if(req->BreakNeeded) {
if((int)req->BreakNeeded) {
SleepUntilResume(type, req->GetBreakSource());
} else {
//Also check if a debugger break request is pending
@ -457,7 +457,7 @@ void Debugger::SleepUntilResume(CpuType sourceCpu, BreakSource source, MemoryOpe
//If SleepUntilResume was called outside of ProcessInstruction, keep running
return;
} else if(IsBreakpointForbidden(source, sourceCpu, operation)) {
ClearPendingBreakRequests();
ClearPendingBreakExceptions();
return;
}
@ -503,7 +503,7 @@ void Debugger::SleepUntilResume(CpuType sourceCpu, BreakSource source, MemoryOpe
bool Debugger::IsBreakpointForbidden(BreakSource source, CpuType sourceCpu, MemoryOperationInfo* operation)
{
if(source != BreakSource::Unspecified && source != BreakSource::CpuStep && source != BreakSource::PpuStep && source != BreakSource::Pause && _breakRequestCount == 0) {
if((source > BreakSource::InternalOperation || source == BreakSource::Breakpoint) && _breakRequestCount == 0) {
BreakpointManager* bp = _debuggers[(int)sourceCpu].Debugger->GetBreakpointManager();
uint32_t pc = GetProgramCounter(sourceCpu, true);
AddressInfo relAddr = { (int32_t)pc, DebugUtilities::GetCpuMemoryType(sourceCpu) };
@ -518,8 +518,8 @@ template<uint8_t accessWidth>
void Debugger::ProcessBreakConditions(CpuType sourceCpu, StepRequest& step, BreakpointManager* bpManager, MemoryOperationInfo& operation, AddressInfo& addressInfo)
{
int breakpointId = bpManager->CheckBreakpoint<accessWidth>(operation, addressInfo, true);
if(_breakRequestCount || _waitForBreakResume || (step.BreakNeeded && (!_debuggers[(int)sourceCpu].Debugger->IgnoreBreakpoints || step.Type == StepType::CpuCycleStep))) {
SleepUntilResume(sourceCpu, step.Source);
if(_breakRequestCount || _waitForBreakResume || ((int)step.BreakNeeded && (!_debuggers[(int)sourceCpu].Debugger->IgnoreBreakpoints || step.Type == StepType::CpuCycleStep))) {
SleepUntilResume(sourceCpu, step.GetBreakSource());
} else {
if(breakpointId >= 0 && !_debuggers[(int)sourceCpu].Debugger->IgnoreBreakpoints) {
SleepUntilResume(sourceCpu, BreakSource::Breakpoint, &operation, breakpointId);
@ -656,11 +656,11 @@ void Debugger::Run()
_waitForBreakResume = false;
}
void Debugger::ClearPendingBreakRequests()
void Debugger::ClearPendingBreakExceptions()
{
for(int i = 0; i <= (int)DebugUtilities::GetLastCpuType(); i++) {
if(_debuggers[i].Debugger) {
_debuggers[i].Debugger->Run();
_debuggers[i].Debugger->GetStepRequest()->ClearException();
}
}
}
@ -692,7 +692,7 @@ void Debugger::Step(CpuType cpuType, int32_t stepCount, StepType type, BreakSour
}
debugger->Step(stepCount, type);
debugger->GetStepRequest()->SetBreakSource(source);
debugger->GetStepRequest()->SetBreakSource(source, false);
}
for(int i = 0; i <= (int)DebugUtilities::GetLastCpuType(); i++) {

View file

@ -99,7 +99,7 @@ private:
bool IsBreakOptionEnabled(BreakSource src);
template<CpuType type> void SleepOnBreakRequest();
void ClearPendingBreakRequests();
void ClearPendingBreakExceptions();
bool IsBreakpointForbidden(BreakSource source, CpuType sourceCpu, MemoryOperationInfo* operation);

View file

@ -1529,6 +1529,8 @@ namespace Mesen.Interop
Pause,
CpuStep,
PpuStep,
Irq,
Nmi,
InternalOperation,
BreakOnBrk,
@ -1537,9 +1539,6 @@ namespace Mesen.Interop
BreakOnStp,
BreakOnUninitMemoryRead,
Irq,
Nmi,
GbInvalidOamAccess,
GbInvalidVramAccess,
GbDisableLcdOutsideVblank,