2019-02-14 17:58:33 +00:00
|
|
|
#include <windows.h>
|
|
|
|
#include <setjmp.h>
|
|
|
|
#include "exception_handling.h"
|
|
|
|
|
|
|
|
#define CALL_FIRST 1
|
|
|
|
|
|
|
|
__declspec(thread) jmp_buf jmpBuf;
|
2019-05-02 09:09:57 +00:00
|
|
|
__declspec(thread) DWORD caughtExceptionCode;
|
2019-02-14 17:58:33 +00:00
|
|
|
__declspec(thread) PVOID caughtExceptionAddress;
|
|
|
|
__declspec(thread) DWORD64 caughtInstructionPointer;
|
|
|
|
__declspec(thread) PVOID savedStackPointer;
|
|
|
|
__declspec(thread) BOOL exceptionHandlerInstalled = FALSE;
|
|
|
|
__declspec(thread) BOOL alreadyHandlingException = FALSE;
|
2019-03-01 21:16:32 +00:00
|
|
|
__declspec(thread) PVOID handle;
|
2019-02-14 17:58:33 +00:00
|
|
|
|
|
|
|
void longjmpOutOfHere() {
|
|
|
|
longjmp(jmpBuf, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the current address that we use to jmp, the no inline is important
|
|
|
|
static __declspec(noinline) void *get_callee_frame_address(void) {
|
|
|
|
return _AddressOfReturnAddress();
|
|
|
|
}
|
|
|
|
|
|
|
|
static LONG WINAPI
|
|
|
|
exceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo) {
|
|
|
|
EXCEPTION_RECORD* pExceptionRecord = ExceptionInfo->ExceptionRecord;
|
|
|
|
PCONTEXT pCONTEXT = ExceptionInfo->ContextRecord;
|
2019-05-02 09:09:57 +00:00
|
|
|
caughtExceptionCode = pExceptionRecord->ExceptionCode;
|
2019-02-14 17:58:33 +00:00
|
|
|
caughtExceptionAddress = pExceptionRecord->ExceptionAddress;
|
|
|
|
caughtInstructionPointer = pCONTEXT->Rip;
|
|
|
|
if (alreadyHandlingException == TRUE) {
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
}
|
|
|
|
alreadyHandlingException = TRUE;
|
|
|
|
|
|
|
|
// Basically, here, we coerce the os to resume us into a context that calls `longjmp` instead of just continuing.
|
|
|
|
// Presumably, we cannot `longjmp` out of the signal/exception context, like we can on unix.
|
|
|
|
pCONTEXT->Rip = (uintptr_t)(&longjmpOutOfHere);
|
|
|
|
pCONTEXT->Rsp = (uintptr_t)(savedStackPointer);
|
|
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
|
|
}
|
|
|
|
|
2019-03-01 21:16:32 +00:00
|
|
|
static void removeExceptionHandler() {
|
|
|
|
if (exceptionHandlerInstalled == FALSE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
RemoveVectoredExceptionHandler(handle);
|
|
|
|
exceptionHandlerInstalled = FALSE;
|
|
|
|
}
|
|
|
|
|
2019-02-14 17:58:33 +00:00
|
|
|
uint8_t callProtected(trampoline_t trampoline,
|
|
|
|
const struct wasmer_instance_context_t* ctx,
|
|
|
|
const struct func_t* func,
|
|
|
|
const uint64_t* param_vec,
|
|
|
|
uint64_t* return_vec,
|
|
|
|
struct call_protected_result_t* out_result) {
|
|
|
|
|
|
|
|
// install exception handler
|
|
|
|
if (exceptionHandlerInstalled == FALSE) {
|
|
|
|
exceptionHandlerInstalled = TRUE;
|
2019-03-01 21:16:32 +00:00
|
|
|
handle = AddVectoredExceptionHandler(CALL_FIRST, exceptionHandler);
|
2019-02-14 17:58:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// jmp jmp jmp!
|
2019-05-02 09:09:57 +00:00
|
|
|
int status = setjmp(jmpBuf);
|
|
|
|
if (status == 0) // 0 means the original call
|
|
|
|
{
|
2019-02-14 17:58:33 +00:00
|
|
|
// save the stack pointer
|
|
|
|
savedStackPointer = get_callee_frame_address();
|
|
|
|
trampoline(ctx, func, param_vec, return_vec);
|
|
|
|
out_result->code = 0;
|
2019-03-15 21:10:17 +00:00
|
|
|
out_result->exception_address = 0;
|
|
|
|
out_result->instruction_pointer = 0;
|
2019-03-01 21:16:32 +00:00
|
|
|
|
|
|
|
removeExceptionHandler();
|
2019-02-14 17:58:33 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-05-02 09:09:57 +00:00
|
|
|
out_result->code = (uint64_t)caughtExceptionCode;
|
2019-03-15 21:10:17 +00:00
|
|
|
out_result->exception_address = (uint64_t)caughtExceptionAddress;
|
|
|
|
out_result->instruction_pointer = caughtInstructionPointer;
|
2019-02-14 17:58:33 +00:00
|
|
|
|
|
|
|
caughtExceptionAddress = 0;
|
|
|
|
caughtInstructionPointer = 0;
|
|
|
|
|
2019-03-01 21:16:32 +00:00
|
|
|
removeExceptionHandler();
|
2019-02-14 17:58:33 +00:00
|
|
|
return FALSE;
|
2019-05-02 09:09:57 +00:00
|
|
|
}
|