Hello,
I'm at the last hurdle for my JIT-implementation, for now. I've implemented exception-handling based on this article: x64 exception handling
I'm registering the unwind-information using RtlAddFunctionTable, specifying a “language-specific handler" that invokes the necessary cleanup-code:
EXCEPTION_DISPOSITION handleException(PEXCEPTION_RECORD exceptionRecord, ULONG64 establisherFrame, PCONTEXT contextRecord, PDISPATCHER_CONTEXT dispatcherContext)
{
auto& state = *reinterpret_cast<ExecutionStateJIT*>(contextRecord->Rbx);
// TODO: compile into handler directly
const auto* pAddress = (const char*)dispatcherContext->ControlPc;
const auto* pHandler = g_interpreter.GetExceptionHandlerAddress(pAddress);
if (const auto* pResumeAddress = (JitExceptionFunction(pHandler))(state))
// TODO: implement => doesn't work
// return (const char*)EXCEPTION_DISPOSITION::ExceptionContinueExecution;
else
return (const char*)EXCEPTION_DISPOSITION::ExceptionContinueSearch;
Now the basic process is working, when I throw an exception:
throw AERuntimeError(sys::toA(strMessage));
Then the unwind is performed properly, and the exception is passed from my jit-code into the c++ that is calling it. However, I can't seem to find a way how to prevent the exception from being passed on. Conceptually, I have the ability to specify a “catch” block in my visual-scripting language, akin to:
try
{
throwingMethod();
}
catch (...) {} // do nothing
// continue
But I'm failing to understand how I would be able to implement this with the exception-handling available to me. EXCEPTION_DISPOSITION is extremely limited in its return-values. The only option that comes close is “ExceptionContinueExecution”, but this would not be the correct address (the address I actually want to resume at is returned by my own handler), and it also fails since for some reason the exception that the handler receives is marked as EXCEPTION_NONCONTINUABLE - which I don't quite understand the difference, there's only a short remark at the end of https://docs.microsoft.com/en-us/windows/win32/debug/exception-handling .
I've tried to look at how the normal c++ runtimes handles this kind of situation, but it seems to invoke an entirely different routine. The stack for the exception-code above in c++ is:
vcruntime140_1d.dll!_CallSettingFrame_LookupContinuationIndex() Line 98 Unknown
vcruntime140_1d.dll!__FrameHandler4::CxxCallCatchBlock(_EXCEPTION_RECORD * pExcept) Line 1393 C++
ntdll.dll!RcConsolidateFrames?() Unknown
while the callstack for my handler ends up being:
ntdll.dll!RtlpExecuteHandlerForException?() Unknown
ntdll.dll!RtlDispatchException() Unknown
ntdll.dll!KiUserExceptionDispatch?() Unknown
KernelBase.dll!RaiseException?() Unknown
vcruntime140d.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 75 C++
Which makes sense that its different, but not why the c++-stack does not have the _CxxThrowException at all anymore (which means that I cannot really implement a custom “jump to my address”-solution without seriously messing with the registered callstack).
So, does somebody have any experience using this exception-handling process for my specific use-case?