Merge pull request #4340 from sepalani/step_timeout
CodeWindow: Fix step out issues
This commit is contained in:
commit
0705c53681
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue