I'm working on an Xbox1 emulator in Delphi, and because I run the games on the local CPU I have to create a failsafe for ring0 instructions that can occur inside the game-code.
To be able to trap these instructions, I've learned that SetUnhandledExceptionFilter can register a function that's going to be called on non-Delphi exceptions (provided I set JITEnable to a value above 0). The signature of the registered callback function reads :
function ExceptionFilter(E: LPEXCEPTION_POINTERS): Integer; stdcall;
Inside that function, I can test for illegal instructions like this :
// STATUS_PRIVILEGED_INSTRUCTION = $C0000096
if E.ExceptionRecord.ExceptionCode = STATUS_PRIVILEGED_INSTRUCTION then
One of the offending instructions is WVINDB ($0F,$09) which I can detect like this :
// See if the instruction pointer is a WBINVD opcode :
if (PAnsiChar(E.ExceptionRecord.ExceptionAddress)[0] = #$0F)
and (PAnsiChar(E.ExceptionRecord.ExceptionAddress)[1] = #$09) then
This all works (provided I run this outside the debugger) but I can't get the code to execute beyond the failing instruction - I tried it like this:
begin
// Skip the WBINVD instruction, and continue execution :
Inc(DWORD(E.ExceptionRecord.ExceptionAddress), 2);
Result := EXCEPTION_CONTINUE_EXECUTION;
Exit;
end;
Alas, that doesn't work. Actually, I would have used the real instruction pointer (E.ContextRecord.Eip), but somehow the entire ContextRecord doesn't seem populated.
What can I do so this does work as intended?
PS: When running with the debugger, I would expect this code to end up in my ExceptionFilter routine, but it doesn't - it only works without the debugger; Why's that?
DebugHook := 0; // Act as if there's no debugger
// Trigger a privileged instruction exception via this ring0 instruction :
asm
WBINVD
end;
// Prove that my exception-filter worked :
ShowMessage('WBINVD succesfully ignored!');
SetUnhandledExceptionFilter seems to be some kind of Delphi wrapper, maybe you have more luck if you do it directly?
You can register your own Exception handler with AddVectoredExceptionHandler, this will call a callback function that gives you an EXCEPTION_POINTERS structure. The Context member of that structure returns ao EIP which you can modify.
If you return EXCEPTION_CONTINUE_EXECUTION in the Callback execution continues at the given EIP.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With