Merge pull request #4340 from sepalani/step_timeout

CodeWindow: Fix step out issues
This commit is contained in:
Anthony 2016-12-01 13:32:44 -06:00 committed by GitHub
commit 0705c53681
1 changed files with 34 additions and 17 deletions

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <array> #include <array>
#include <chrono>
#include <cstdio> #include <cstdio>
#include <string> #include <string>
#include <vector> #include <vector>
@ -302,6 +303,7 @@ void CCodeWindow::SingleStep()
CPU::StepOpcode(&sync_event); CPU::StepOpcode(&sync_event);
sync_event.WaitFor(std::chrono::milliseconds(20)); sync_event.WaitFor(std::chrono::milliseconds(20));
PowerPC::SetMode(old_mode); PowerPC::SetMode(old_mode);
Core::DisplayMessage(_("Step successful!").ToStdString(), 2000);
// Will get a IDM_UPDATE_DISASM_DIALOG. Don't update the GUI here. // Will get a IDM_UPDATE_DISASM_DIALOG. Don't update the GUI here.
} }
} }
@ -316,6 +318,7 @@ void CCodeWindow::StepOver()
PowerPC::breakpoints.ClearAllTemporary(); PowerPC::breakpoints.ClearAllTemporary();
PowerPC::breakpoints.Add(PC + 4, true); PowerPC::breakpoints.Add(PC + 4, true);
CPU::EnableStepping(false); CPU::EnableStepping(false);
Core::DisplayMessage(_("Step over in progress...").ToStdString(), 2000);
} }
else else
{ {
@ -324,9 +327,12 @@ void CCodeWindow::StepOver()
} }
} }
// Returns true on a blr or on a bclr that evaluates to true. // Returns true on a rfi, blr or on a bclr that evaluates to true.
static bool WillInstructionReturn(UGeckoInstruction inst) static bool WillInstructionReturn(UGeckoInstruction inst)
{ {
// Is a rfi instruction
if (inst.hex == 0x4C000064u)
return true;
bool counter = (inst.BO_2 >> 2 & 1) != 0 || (CTR != 0) != ((inst.BO_2 >> 1 & 1) != 0); bool counter = (inst.BO_2 >> 2 & 1) != 0 || (CTR != 0) != ((inst.BO_2 >> 1 & 1) != 0);
bool condition = inst.BO_2 >> 4 != 0 || GetCRBit(inst.BI_2) == (inst.BO_2 >> 3 & 1); bool condition = inst.BO_2 >> 4 != 0 || GetCRBit(inst.BI_2) == (inst.BO_2 >> 3 & 1);
bool isBclr = inst.OPCD_7 == 0b010011 && (inst.hex >> 1 & 0b10000) != 0; bool isBclr = inst.OPCD_7 == 0b010011 && (inst.hex >> 1 & 0b10000) != 0;
@ -340,44 +346,55 @@ void CCodeWindow::StepOut()
CPU::PauseAndLock(true, false); CPU::PauseAndLock(true, false);
PowerPC::breakpoints.ClearAllTemporary(); PowerPC::breakpoints.ClearAllTemporary();
// Keep stepping until the next return instruction or timeout after one second // Keep stepping until the next return instruction or timeout after five seconds
u64 timeout = SystemTimers::GetTicksPerSecond(); using clock = std::chrono::steady_clock;
u64 steps = 0; clock::time_point timeout = clock::now() + std::chrono::seconds(5);
PowerPC::CoreMode old_mode = PowerPC::GetMode(); PowerPC::CoreMode old_mode = PowerPC::GetMode();
PowerPC::SetMode(PowerPC::MODE_INTERPRETER); PowerPC::SetMode(PowerPC::MODE_INTERPRETER);
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC);
// Loop until either the current instruction is a return instruction with no Link flag // Loop until either the current instruction is a return instruction with no Link flag
// or a breakpoint is detected so it can step at the breakpoint. // or a breakpoint is detected so it can step at the breakpoint. If the PC is currently
while (!(WillInstructionReturn(inst)) && steps < timeout && // on a breakpoint, skip it.
!PowerPC::breakpoints.IsAddressBreakPoint(PC)) UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC);
do
{ {
if (WillInstructionReturn(inst))
{
PowerPC::SingleStep();
break;
}
if (inst.LK) if (inst.LK)
{ {
// Step over branches // Step over branches
u32 next_pc = PC + 4; u32 next_pc = PC + 4;
while (PC != next_pc && steps < timeout) do
{ {
PowerPC::SingleStep(); PowerPC::SingleStep();
++steps; } while (PC != next_pc && clock::now() < timeout &&
} !PowerPC::breakpoints.IsAddressBreakPoint(PC));
} }
else else
{ {
PowerPC::SingleStep(); PowerPC::SingleStep();
++steps;
} }
inst = PowerPC::HostRead_Instruction(PC); inst = PowerPC::HostRead_Instruction(PC);
} } while (clock::now() < timeout && !PowerPC::breakpoints.IsAddressBreakPoint(PC));
// If the loop stopped because of a breakpoint, we do not want to step to
// an instruction after it.
if (!PowerPC::breakpoints.IsAddressBreakPoint(PC))
PowerPC::SingleStep();
PowerPC::SetMode(old_mode); PowerPC::SetMode(old_mode);
CPU::PauseAndLock(false, false); CPU::PauseAndLock(false, false);
wxCommandEvent ev(wxEVT_HOST_COMMAND, IDM_UPDATE_DISASM_DIALOG); wxCommandEvent ev(wxEVT_HOST_COMMAND, IDM_UPDATE_DISASM_DIALOG);
GetEventHandler()->ProcessEvent(ev); GetEventHandler()->ProcessEvent(ev);
if (PowerPC::breakpoints.IsAddressBreakPoint(PC))
Core::DisplayMessage(_("Breakpoint encountered! Step out aborted.").ToStdString(), 2000);
else if (clock::now() >= timeout)
Core::DisplayMessage(_("Step out timed out!").ToStdString(), 2000);
else
Core::DisplayMessage(_("Step out successful!").ToStdString(), 2000);
// Update all toolbars in the aui manager // Update all toolbars in the aui manager
Parent->UpdateGUI(); Parent->UpdateGUI();
} }