Debugger: Small other cleanup

Change misleading names.
Fix function usage: Intepreter and Step Out will not check breakpoints in their own wrong way anymore (e.g. breaking on log-only breakpoints).
This commit is contained in:
Martino Fontana 2024-06-15 11:15:23 +02:00
parent 9aeeea3762
commit 8235c38df7
12 changed files with 48 additions and 69 deletions

View File

@ -704,13 +704,13 @@ void SetState(Core::System& system, State state, bool report_state_change)
case State::Paused: case State::Paused:
// NOTE: GetState() will return State::Paused immediately, even before anything has // NOTE: GetState() will return State::Paused immediately, even before anything has
// stopped (including the CPU). // stopped (including the CPU).
system.GetCPU().EnableStepping(true); // Break system.GetCPU().SetStepping(true); // Break
Wiimote::Pause(); Wiimote::Pause();
ResetRumble(); ResetRumble();
break; break;
case State::Running: case State::Running:
{ {
system.GetCPU().EnableStepping(false); system.GetCPU().SetStepping(false);
Wiimote::Resume(); Wiimote::Resume();
break; break;
} }
@ -813,7 +813,7 @@ static bool PauseAndLock(Core::System& system, bool do_lock, bool unpause_on_unl
// The CPU is responsible for managing the Audio and FIFO state so we use its // The CPU is responsible for managing the Audio and FIFO state so we use its
// mechanism to unpause them. If we unpaused the systems above when releasing // mechanism to unpause them. If we unpaused the systems above when releasing
// the locks then they could call CPU::Break which would require detecting it // the locks then they could call CPU::Break which would require detecting it
// and re-pausing with CPU::EnableStepping. // and re-pausing with CPU::SetStepping.
was_unpaused = system.GetCPU().PauseAndLock(false, unpause_on_unlock, true); was_unpaused = system.GetCPU().PauseAndLock(false, unpause_on_unlock, true);
} }

View File

@ -228,7 +228,7 @@ public:
IsPlayingBackFifologWithBrokenEFBCopies = m_parent->m_File->HasBrokenEFBCopies(); IsPlayingBackFifologWithBrokenEFBCopies = m_parent->m_File->HasBrokenEFBCopies();
// Without this call, we deadlock in initialization in dual core, as the FIFO is disabled and // Without this call, we deadlock in initialization in dual core, as the FIFO is disabled and
// thus ClearEfb()'s call to WaitForGPUInactive() never returns // thus ClearEfb()'s call to WaitForGPUInactive() never returns
m_parent->m_system.GetCPU().EnableStepping(false); m_parent->m_system.GetCPU().SetStepping(false);
m_parent->m_CurrentFrame = m_parent->m_FrameRangeStart; m_parent->m_CurrentFrame = m_parent->m_FrameRangeStart;
m_parent->LoadMemory(); m_parent->LoadMemory();
@ -243,7 +243,7 @@ public:
void SingleStep() override void SingleStep() override
{ {
// NOTE: AdvanceFrame() will get stuck forever in Dual Core because the FIFO // NOTE: AdvanceFrame() will get stuck forever in Dual Core because the FIFO
// is disabled by CPU::EnableStepping(true) so the frame never gets displayed. // is disabled by CPU::SetStepping(true) so the frame never gets displayed.
PanicAlertFmtT("Cannot SingleStep the FIFO. Use Frame Advance instead."); PanicAlertFmtT("Cannot SingleStep the FIFO. Use Frame Advance instead.");
} }

View File

@ -88,6 +88,7 @@ void CPUManager::Run()
// Adjust PC for JIT when debugging // Adjust PC for JIT when debugging
// SingleStep so that the "continue", "step over" and "step out" debugger functions // SingleStep so that the "continue", "step over" and "step out" debugger functions
// work when the PC is at a breakpoint at the beginning of the block // work when the PC is at a breakpoint at the beginning of the block
// Don't use PowerPCManager::CheckBreakPoints, otherwise you get double logging
// If watchpoints are enabled, any instruction could be a breakpoint. // If watchpoints are enabled, any instruction could be a breakpoint.
if (power_pc.GetMode() != PowerPC::CoreMode::Interpreter) if (power_pc.GetMode() != PowerPC::CoreMode::Interpreter)
{ {
@ -174,7 +175,7 @@ void CPUManager::Run()
// Requires holding m_state_change_lock // Requires holding m_state_change_lock
void CPUManager::RunAdjacentSystems(bool running) void CPUManager::RunAdjacentSystems(bool running)
{ {
// NOTE: We're assuming these will not try to call Break or EnableStepping. // NOTE: We're assuming these will not try to call Break or SetStepping.
m_system.GetFifo().EmulatorState(running); m_system.GetFifo().EmulatorState(running);
// Core is responsible for shutting down the sound stream. // Core is responsible for shutting down the sound stream.
if (m_state != State::PowerDown) if (m_state != State::PowerDown)
@ -247,7 +248,7 @@ bool CPUManager::SetStateLocked(State s)
return true; return true;
} }
void CPUManager::EnableStepping(bool stepping) void CPUManager::SetStepping(bool stepping)
{ {
std::lock_guard stepping_lock(m_stepping_lock); std::lock_guard stepping_lock(m_stepping_lock);
std::unique_lock state_lock(m_state_change_lock); std::unique_lock state_lock(m_state_change_lock);
@ -290,7 +291,7 @@ void CPUManager::Break()
void CPUManager::Continue() void CPUManager::Continue()
{ {
EnableStepping(false); SetStepping(false);
Core::CallOnStateChangedCallbacks(Core::State::Running); Core::CallOnStateChangedCallbacks(Core::State::Running);
} }

View File

@ -62,10 +62,10 @@ public:
void StepOpcode(Common::Event* event = nullptr); void StepOpcode(Common::Event* event = nullptr);
// Enable or Disable Stepping. [Will deadlock if called from a system thread] // Enable or Disable Stepping. [Will deadlock if called from a system thread]
void EnableStepping(bool stepping); void SetStepping(bool stepping);
// Breakpoint activation for system threads. Similar to EnableStepping(true). // Breakpoint activation for system threads. Similar to SetStepping(true).
// NOTE: Unlike EnableStepping, this does NOT synchronize with the CPU Thread // NOTE: Unlike SetStepping, this does NOT synchronize with the CPU Thread
// which enables it to avoid deadlocks but also makes it less safe so it // which enables it to avoid deadlocks but also makes it less safe so it
// should not be used by the Host. // should not be used by the Host.
void Break(); void Break();
@ -91,7 +91,7 @@ public:
// Return value for do_lock == true is whether the state was State::Running or not. // Return value for do_lock == true is whether the state was State::Running or not.
// Return value for do_lock == false is whether the state was changed *to* State::Running or not. // Return value for do_lock == false is whether the state was changed *to* State::Running or not.
// Cannot be used by System threads as it will deadlock. It is threadsafe otherwise. // Cannot be used by System threads as it will deadlock. It is threadsafe otherwise.
// "control_adjacent" causes PauseAndLock to behave like EnableStepping by modifying the // "control_adjacent" causes PauseAndLock to behave like SetStepping by modifying the
// state of the Audio and FIFO subsystems as well. // state of the Audio and FIFO subsystems as well.
bool PauseAndLock(bool do_lock, bool unpause_on_unlock = true, bool control_adjacent = false); bool PauseAndLock(bool do_lock, bool unpause_on_unlock = true, bool control_adjacent = false);
@ -110,9 +110,9 @@ private:
// Read access is unsynchronized. // Read access is unsynchronized.
State m_state = State::PowerDown; State m_state = State::PowerDown;
// Synchronizes EnableStepping and PauseAndLock so only one instance can be // Synchronizes SetStepping and PauseAndLock so only one instance can be
// active at a time. Simplifies code by eliminating several edge cases where // active at a time. Simplifies code by eliminating several edge cases where
// the EnableStepping(true)/PauseAndLock(true) case must release the state lock // the SetStepping(true)/PauseAndLock(true) case must release the state lock
// and wait for the CPU Thread which would otherwise require additional flags. // and wait for the CPU Thread which would otherwise require additional flags.
// NOTE: When using the stepping lock, it must always be acquired first. If // NOTE: When using the stepping lock, it must always be acquired first. If
// the lock is acquired after the state lock then that is guaranteed to // the lock is acquired after the state lock then that is guaranteed to

View File

@ -249,8 +249,7 @@ bool CachedInterpreter::CheckProgramException(CachedInterpreter& cached_interpre
bool CachedInterpreter::CheckBreakpoint(CachedInterpreter& cached_interpreter, u32 data) bool CachedInterpreter::CheckBreakpoint(CachedInterpreter& cached_interpreter, u32 data)
{ {
cached_interpreter.m_system.GetPowerPC().CheckBreakPoints(); if (cached_interpreter.m_system.GetPowerPC().CheckAndHandleBreakPoints())
if (cached_interpreter.m_system.GetCPU().GetState() != CPU::State::Running)
{ {
cached_interpreter.m_ppc_state.downcount -= data; cached_interpreter.m_ppc_state.downcount -= data;
return true; return true;

View File

@ -865,7 +865,7 @@ static void WriteMemory(const Core::CPUThreadGuard& guard)
static void Step() static void Step()
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
system.GetCPU().EnableStepping(true); system.GetCPU().SetStepping(true);
Core::CallOnStateChangedCallbacks(Core::State::Paused); Core::CallOnStateChangedCallbacks(Core::State::Paused);
} }

View File

@ -261,38 +261,8 @@ void Interpreter::Run()
s_pc_vec.erase(s_pc_vec.begin()); s_pc_vec.erase(s_pc_vec.begin());
#endif #endif
// 2: check for breakpoint if (power_pc.CheckAndHandleBreakPoints())
if (power_pc.GetBreakPoints().IsAddressBreakPoint(m_ppc_state.pc))
{
#ifdef SHOW_HISTORY
NOTICE_LOG_FMT(POWERPC, "----------------------------");
NOTICE_LOG_FMT(POWERPC, "Blocks:");
for (const u32 entry : s_pc_block_vec)
NOTICE_LOG_FMT(POWERPC, "PC: {:#010x}", entry);
NOTICE_LOG_FMT(POWERPC, "----------------------------");
NOTICE_LOG_FMT(POWERPC, "Steps:");
for (size_t j = 0; j < s_pc_vec.size(); j++)
{
// Write space
if (j > 0)
{
if (s_pc_vec[j] != s_pc_vec[(j - 1) + 4]
NOTICE_LOG_FMT(POWERPC, "");
}
NOTICE_LOG_FMT(POWERPC, "PC: {:#010x}", s_pc_vec[j]);
}
#endif
INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", m_ppc_state.pc);
cpu.Break();
if (GDBStub::IsActive())
GDBStub::TakeControl();
if (power_pc.GetBreakPoints().IsTempBreakPoint(m_ppc_state.pc))
power_pc.GetBreakPoints().Remove(m_ppc_state.pc);
Host_UpdateDisasmDialog();
return; return;
}
cycles += SingleStepInner(); cycles += SingleStepInner();
} }
m_ppc_state.downcount -= cycles; m_ppc_state.downcount -= cycles;

View File

@ -1043,7 +1043,7 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
MOV(32, PPCSTATE(pc), Imm32(op.address)); MOV(32, PPCSTATE(pc), Imm32(op.address));
ABI_PushRegistersAndAdjustStack({}, 0); ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionP(PowerPC::CheckBreakPointsFromJIT, &power_pc); ABI_CallFunctionP(PowerPC::CheckAndHandleBreakPointsFromJIT, &power_pc);
ABI_PopRegistersAndAdjustStack({}, 0); ABI_PopRegistersAndAdjustStack({}, 0);
MOV(64, R(RSCRATCH), ImmPtr(cpu.GetStatePtr())); MOV(64, R(RSCRATCH), ImmPtr(cpu.GetStatePtr()));
CMP(32, MatR(RSCRATCH), Imm32(Common::ToUnderlying(CPU::State::Running))); CMP(32, MatR(RSCRATCH), Imm32(Common::ToUnderlying(CPU::State::Running)));

View File

@ -1249,7 +1249,7 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
MOVI2R(DISPATCHER_PC, op.address); MOVI2R(DISPATCHER_PC, op.address);
STP(IndexType::Signed, DISPATCHER_PC, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); STP(IndexType::Signed, DISPATCHER_PC, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc));
ABI_CallFunction(&PowerPC::CheckBreakPointsFromJIT, &m_system.GetPowerPC()); ABI_CallFunction(&PowerPC::CheckAndHandleBreakPointsFromJIT, &m_system.GetPowerPC());
LDR(IndexType::Unsigned, ARM64Reg::W0, ARM64Reg::X0, LDR(IndexType::Unsigned, ARM64Reg::W0, ARM64Reg::X0,
MOVPage2R(ARM64Reg::X0, cpu.GetStatePtr())); MOVPage2R(ARM64Reg::X0, cpu.GetStatePtr()));

View File

@ -629,19 +629,13 @@ void PowerPCManager::CheckExternalExceptions()
m_system.GetJitInterface().UpdateMembase(); m_system.GetJitInterface().UpdateMembase();
} }
void PowerPCManager::CheckBreakPoints() bool PowerPCManager::CheckBreakPoints()
{ {
const TBreakPoint* bp = m_breakpoints.GetBreakpoint(m_ppc_state.pc); const TBreakPoint* bp = m_breakpoints.GetBreakpoint(m_ppc_state.pc);
if (!bp || !bp->is_enabled || !EvaluateCondition(m_system, bp->condition)) if (!bp || !bp->is_enabled || !EvaluateCondition(m_system, bp->condition))
return; return false;
if (bp->break_on_hit)
{
m_system.GetCPU().Break();
if (GDBStub::IsActive())
GDBStub::TakeControl();
}
if (bp->log_on_hit) if (bp->log_on_hit)
{ {
NOTICE_LOG_FMT(MEMMAP, NOTICE_LOG_FMT(MEMMAP,
@ -652,8 +646,21 @@ void PowerPCManager::CheckBreakPoints()
m_ppc_state.gpr[8], m_ppc_state.gpr[9], m_ppc_state.gpr[10], m_ppc_state.gpr[11], m_ppc_state.gpr[8], m_ppc_state.gpr[9], m_ppc_state.gpr[10], m_ppc_state.gpr[11],
m_ppc_state.gpr[12], LR(m_ppc_state)); m_ppc_state.gpr[12], LR(m_ppc_state));
} }
if (m_breakpoints.IsTempBreakPoint(m_ppc_state.pc)) if (bp->break_on_hit)
m_breakpoints.Remove(m_ppc_state.pc); return true;
return false;
}
bool PowerPCManager::CheckAndHandleBreakPoints()
{
if (CheckBreakPoints())
{
m_system.GetCPU().Break();
if (GDBStub::IsActive())
GDBStub::TakeControl();
return true;
}
return false;
} }
void PowerPCState::SetSR(u32 index, u32 value) void PowerPCState::SetSR(u32 index, u32 value)
@ -722,8 +729,8 @@ void CheckExternalExceptionsFromJIT(PowerPCManager& power_pc)
power_pc.CheckExternalExceptions(); power_pc.CheckExternalExceptions();
} }
void CheckBreakPointsFromJIT(PowerPCManager& power_pc) void CheckAndHandleBreakPointsFromJIT(PowerPCManager& power_pc)
{ {
power_pc.CheckBreakPoints(); power_pc.CheckAndHandleBreakPoints();
} }
} // namespace PowerPC } // namespace PowerPC

View File

@ -281,7 +281,10 @@ public:
void SingleStep(); void SingleStep();
void CheckExceptions(); void CheckExceptions();
void CheckExternalExceptions(); void CheckExternalExceptions();
void CheckBreakPoints(); // Evaluate the breakpoints in order to log. Returns whether it would break.
bool CheckBreakPoints();
// Evaluate the breakpoints in order to log and/or break. Returns whether it breaks.
bool CheckAndHandleBreakPoints();
void RunLoop(); void RunLoop();
u64 ReadFullTimeBaseValue() const; u64 ReadFullTimeBaseValue() const;
@ -330,7 +333,7 @@ void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst,
void CheckExceptionsFromJIT(PowerPCManager& power_pc); void CheckExceptionsFromJIT(PowerPCManager& power_pc);
void CheckExternalExceptionsFromJIT(PowerPCManager& power_pc); void CheckExternalExceptionsFromJIT(PowerPCManager& power_pc);
void CheckBreakPointsFromJIT(PowerPCManager& power_pc); void CheckAndHandleBreakPointsFromJIT(PowerPCManager& power_pc);
// Easy register access macros. // Easy register access macros.
#define HID0(ppc_state) ((UReg_HID0&)(ppc_state).spr[SPR_HID0]) #define HID0(ppc_state) ((UReg_HID0&)(ppc_state).spr[SPR_HID0])

View File

@ -484,7 +484,7 @@ void CodeWidget::StepOver()
auto& breakpoints = m_system.GetPowerPC().GetBreakPoints(); auto& breakpoints = m_system.GetPowerPC().GetBreakPoints();
breakpoints.ClearAllTemporary(); breakpoints.ClearAllTemporary();
breakpoints.Add(m_system.GetPPCState().pc + 4, true); breakpoints.Add(m_system.GetPPCState().pc + 4, true);
cpu.EnableStepping(false); cpu.SetStepping(false);
Core::DisplayMessage(tr("Step over in progress...").toStdString(), 2000); Core::DisplayMessage(tr("Step over in progress...").toStdString(), 2000);
} }
else else
@ -547,8 +547,7 @@ void CodeWidget::StepOut()
do do
{ {
power_pc.SingleStep(); power_pc.SingleStep();
} while (ppc_state.pc != next_pc && clock::now() < timeout && } while (ppc_state.pc != next_pc && clock::now() < timeout && !power_pc.CheckBreakPoints());
!breakpoints.IsAddressBreakPoint(ppc_state.pc));
} }
else else
{ {
@ -556,14 +555,14 @@ void CodeWidget::StepOut()
} }
inst = PowerPC::MMU::HostRead_Instruction(guard, ppc_state.pc); inst = PowerPC::MMU::HostRead_Instruction(guard, ppc_state.pc);
} while (clock::now() < timeout && !breakpoints.IsAddressBreakPoint(ppc_state.pc)); } while (clock::now() < timeout && !power_pc.CheckBreakPoints());
power_pc.SetMode(old_mode); power_pc.SetMode(old_mode);
} }
emit Host::GetInstance()->UpdateDisasmDialog(); emit Host::GetInstance()->UpdateDisasmDialog();
if (breakpoints.IsAddressBreakPoint(ppc_state.pc)) if (power_pc.CheckBreakPoints())
Core::DisplayMessage(tr("Breakpoint encountered! Step out aborted.").toStdString(), 2000); Core::DisplayMessage(tr("Breakpoint encountered! Step out aborted.").toStdString(), 2000);
else if (clock::now() >= timeout) else if (clock::now() >= timeout)
Core::DisplayMessage(tr("Step out timed out!").toStdString(), 2000); Core::DisplayMessage(tr("Step out timed out!").toStdString(), 2000);