mirror of https://github.com/PCSX2/pcsx2.git
Fix for broken stack unwinding in the MSVC debugger in and around the EE recompiler. Also sped up debug mode execution a bit by removing some per-block recompiled code overhead that we like almost never use anyway. (it can be re-enabled through the ini for now)
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3386 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
cc06570bd4
commit
4352a3927c
|
@ -343,7 +343,9 @@ struct Pcsx2Config
|
|||
fpuFullMode :1;
|
||||
|
||||
bool
|
||||
StackFrameChecks:1;
|
||||
StackFrameChecks:1,
|
||||
PreBlockCheckEE :1,
|
||||
PreBlockCheckIOP:1;
|
||||
BITFIELD_END
|
||||
|
||||
RecompilerOptions();
|
||||
|
|
|
@ -94,7 +94,8 @@ Pcsx2Config::RecompilerOptions::RecompilerOptions()
|
|||
{
|
||||
bitset = 0;
|
||||
|
||||
StackFrameChecks = false;
|
||||
//StackFrameChecks = false;
|
||||
//PreBlockCheckEE = false;
|
||||
|
||||
// All recs are enabled by default.
|
||||
|
||||
|
@ -173,6 +174,8 @@ void Pcsx2Config::RecompilerOptions::LoadSave( IniInterface& ini )
|
|||
IniBitBool( fpuFullMode );
|
||||
|
||||
IniBitBool( StackFrameChecks );
|
||||
IniBitBool( PreBlockCheckEE );
|
||||
IniBitBool( PreBlockCheckIOP );
|
||||
}
|
||||
|
||||
Pcsx2Config::CpuOptions::CpuOptions()
|
||||
|
|
|
@ -865,8 +865,6 @@ static void recShutdown()
|
|||
s_nInstCacheSize = 0;
|
||||
}
|
||||
|
||||
u32 g_psxlastpc = 0;
|
||||
|
||||
static void iopClearRecLUT(BASEBLOCK* base, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
|
@ -1167,7 +1165,7 @@ void psxRecompileNextInstruction(int delayslot)
|
|||
_clearNeededX86regs();
|
||||
}
|
||||
|
||||
static void printfn()
|
||||
static void __fastcall PreBlockCheck( u32 blockpc )
|
||||
{
|
||||
#ifdef PCSX2_DEBUG
|
||||
extern void iDumpPsxRegisters(u32 startpc, u32 temp);
|
||||
|
@ -1178,16 +1176,16 @@ static void printfn()
|
|||
|
||||
//*(int*)PSXM(0x27990) = 1; // enables cdvd bios output for scph10000
|
||||
|
||||
if( (psxdump&2) && lastrec != g_psxlastpc )
|
||||
if( (psxdump&2) && lastrec != blockpc )
|
||||
{
|
||||
curcount++;
|
||||
|
||||
if( curcount > skip ) {
|
||||
iDumpPsxRegisters(g_psxlastpc, 1);
|
||||
iDumpPsxRegisters(blockpc, 1);
|
||||
curcount = 0;
|
||||
}
|
||||
|
||||
lastrec = g_psxlastpc;
|
||||
lastrec = blockpc;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1235,8 +1233,8 @@ static void __fastcall iopRecRecompile( const u32 startpc )
|
|||
|
||||
if( IsDebugBuild )
|
||||
{
|
||||
MOV32ItoM((uptr)&g_psxlastpc, psxpc);
|
||||
CALLFunc((uptr)printfn);
|
||||
xMOV(ecx, psxpc);
|
||||
xCALL(PreBlockCheck);
|
||||
}
|
||||
|
||||
// go until the next branch
|
||||
|
|
|
@ -336,7 +336,6 @@ void recCall( void (*func)() )
|
|||
|
||||
static void __fastcall recRecompile( const u32 startpc );
|
||||
|
||||
static u32 g_lastpc = 0;
|
||||
static u32 s_store_ebp, s_store_esp;
|
||||
|
||||
// Recompiled code buffer for EE recompiler dispatchers!
|
||||
|
@ -382,7 +381,7 @@ static void _DynGen_StackFrameCheck()
|
|||
xCMP( ebp, ptr[&s_store_ebp] );
|
||||
xForwardJE8 skipassert_ebp;
|
||||
|
||||
xMOV( ecx, 1 ); // 1 specifies EBP
|
||||
xMOV( ecx, 1 ); // 1 specifies EBP
|
||||
xMOV( edx, ebp );
|
||||
xCALL( StackFrameCheckFailed );
|
||||
xMOV( ebp, ptr[&s_store_ebp] ); // half-hearted frame recovery attempt!
|
||||
|
@ -394,7 +393,7 @@ static void _DynGen_StackFrameCheck()
|
|||
xCMP( esp, ptr[&s_store_esp] );
|
||||
xForwardJE8 skipassert_esp;
|
||||
|
||||
xXOR( ecx, ecx ); // 0 specifies ESP
|
||||
xXOR( ecx, ecx ); // 0 specifies ESP
|
||||
xMOV( edx, esp );
|
||||
xCALL( StackFrameCheckFailed );
|
||||
xMOV( esp, ptr[&s_store_esp] ); // half-hearted frame recovery attempt!
|
||||
|
@ -447,6 +446,8 @@ static DynGenFunc* _DynGen_DispatcherReg()
|
|||
|
||||
static DynGenFunc* _DynGen_EnterRecompiledCode()
|
||||
{
|
||||
pxAssumeDev( DispatcherReg != NULL, "Dynamically generated dispatchers are required prior to generating EnterRecompiledCode!" );
|
||||
|
||||
u8* retval = xGetAlignedCallTarget();
|
||||
|
||||
// "standard" frame pointer setup for aligned stack: Record the original
|
||||
|
@ -463,26 +464,34 @@ static DynGenFunc* _DynGen_EnterRecompiledCode()
|
|||
// (parameters for those calls can be stored there!) [currently no cdecl functions are
|
||||
// used -- we do everything through __fastcall)
|
||||
|
||||
xSUB( esp, 0x30 );
|
||||
static const int cdecl_reserve = 0x00;
|
||||
xSUB( esp, 0x20 + cdecl_reserve );
|
||||
|
||||
xMOV( ptr[ebp-12], edi );
|
||||
xMOV( ptr[ebp-8], esi );
|
||||
xMOV( ptr[ebp-4], ebx );
|
||||
|
||||
// Simulate a CALL function by pushing the call address and EBP onto the stack.
|
||||
xMOV( ptr32[esp+0x1c], 0xffeeff );
|
||||
// (the dummy address here is filled in later right before we generate the LEAVE code)
|
||||
xMOV( ptr32[esp+0x0c+cdecl_reserve], 0xdeadbeef );
|
||||
uptr& imm = *(uptr*)(xGetPtr()-4);
|
||||
|
||||
// This part simulates the "normal" stackframe prep of "push ebp, mov ebp, esp"
|
||||
xMOV( ptr32[esp+0x18], ebp );
|
||||
xLEA( ebp, ptr32[esp+0x18] );
|
||||
// It is done here because we can't really generate that stuff from the Dispatchers themselves.
|
||||
xMOV( ptr32[esp+0x08+cdecl_reserve], ebp );
|
||||
xLEA( ebp, ptr32[esp+0x08+cdecl_reserve] );
|
||||
|
||||
xMOV( ptr[&s_store_esp], esp );
|
||||
xMOV( ptr[&s_store_ebp], ebp );
|
||||
|
||||
xJMP( ptr32[&DispatcherReg] );
|
||||
xJMP( DispatcherReg );
|
||||
|
||||
xAlignCallTarget();
|
||||
|
||||
// This dummy CALL is unreachable code that some debuggers (MSVC2008) need in order to
|
||||
// unwind the stack properly. This is effectively the call that we simulate above.
|
||||
if( IsDevBuild ) xCALL( DispatcherReg );
|
||||
|
||||
imm = (uptr)xGetPtr();
|
||||
ExitRecompiledCode = (DynGenFunc*)xGetPtr();
|
||||
|
||||
|
@ -1240,7 +1249,10 @@ void recompileNextInstruction(int delayslot)
|
|||
s_nEndBlock = pc;
|
||||
}
|
||||
|
||||
static void printfn()
|
||||
// (Called from recompiled code)]
|
||||
// This function is called from the recompiler prior to starting execution of *every* recompiled block.
|
||||
// Calling of this function can be enabled or disabled through the use of EmuConfig.Recompiler.PreBlockChecks
|
||||
static void __fastcall PreBlockCheck( u32 blockpc )
|
||||
{
|
||||
static int lastrec = 0;
|
||||
static int curcount = 0;
|
||||
|
@ -1248,21 +1260,21 @@ static void printfn()
|
|||
|
||||
pxAssert(!Registers::Saved());
|
||||
|
||||
//pxAssert( cpuRegs.pc != 0x80001300 );
|
||||
|
||||
if( (dumplog&2) && g_lastpc != 0x81fc0 ) {//&& lastrec != g_lastpc ) {
|
||||
/*if( blockpc != 0x81fc0 ) {//&& lastrec != g_lastpc ) {
|
||||
curcount++;
|
||||
|
||||
if( curcount > skip ) {
|
||||
iDumpRegisters(g_lastpc, 1);
|
||||
iDumpRegisters(blockpc, 1);
|
||||
curcount = 0;
|
||||
}
|
||||
|
||||
lastrec = g_lastpc;
|
||||
}
|
||||
lastrec = blockpc;
|
||||
}*/
|
||||
}
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
// Array of cpuRegs.pc block addresses to dump. USeful for selectively dumping potential
|
||||
// problem blocks, and seeing what the MIPS code equates to.
|
||||
static u32 s_recblocks[] = {0};
|
||||
#endif
|
||||
|
||||
|
@ -1381,16 +1393,15 @@ static void __fastcall recRecompile( const u32 startpc )
|
|||
_initXMMregs();
|
||||
_initMMXregs();
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
// for debugging purposes
|
||||
MOV32ItoM((uptr)&g_lastpc, pc);
|
||||
CALLFunc((uptr)printfn);
|
||||
if( EmuConfig.Recompiler.PreBlockCheckEE )
|
||||
{
|
||||
// per-block dump checks, for debugging purposes.
|
||||
// [TODO] : These must be enabled from the GUI or INI to be used, otherwise the
|
||||
// code that calls PreBlockCheck will not be generated.
|
||||
|
||||
// CMP32MtoR(EBP, (uptr)&s_uSaveEBP);
|
||||
// j8Ptr[0] = JE8(0);
|
||||
// CALLFunc((uptr)badespfn);
|
||||
// x86SetJ8(j8Ptr[0]);
|
||||
#endif
|
||||
xMOV(ecx, pc);
|
||||
xCALL(PreBlockCheck);
|
||||
}
|
||||
|
||||
// go until the next branch
|
||||
i = startpc;
|
||||
|
@ -1831,7 +1842,7 @@ StartRecomp:
|
|||
// The only *safe* way to throw exceptions from the context of recompiled code.
|
||||
// The exception is cached and the recompiler is exited safely using either an
|
||||
// SEH unwind (MSW) or setjmp/longjmp (GCC).
|
||||
void recThrowException( const BaseR5900Exception& ex )
|
||||
static void recThrowException( const BaseR5900Exception& ex )
|
||||
{
|
||||
if (!m_recExecutingCode) ex.Rethrow();
|
||||
|
||||
|
|
Loading…
Reference in New Issue