-
Notifications
You must be signed in to change notification settings - Fork 811
/
exception_handling.c
86 lines (72 loc) · 2.76 KB
/
exception_handling.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <windows.h>
#include <setjmp.h>
#include "exception_handling.h"
#define CALL_FIRST 1
__declspec(thread) jmp_buf jmpBuf;
__declspec(thread) PVOID caughtExceptionAddress;
__declspec(thread) DWORD64 caughtInstructionPointer;
__declspec(thread) PVOID savedStackPointer;
__declspec(thread) BOOL exceptionHandlerInstalled = FALSE;
__declspec(thread) BOOL alreadyHandlingException = FALSE;
__declspec(thread) PVOID handle;
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;
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;
}
static void removeExceptionHandler() {
if (exceptionHandlerInstalled == FALSE) {
return;
}
RemoveVectoredExceptionHandler(handle);
exceptionHandlerInstalled = FALSE;
}
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;
handle = AddVectoredExceptionHandler(CALL_FIRST, exceptionHandler);
}
// jmp jmp jmp!
int signum = setjmp(jmpBuf);
if (signum == 0) {
// save the stack pointer
savedStackPointer = get_callee_frame_address();
trampoline(ctx, func, param_vec, return_vec);
out_result->code = 0;
out_result->exception_address = 0;
out_result->instruction_pointer = 0;
removeExceptionHandler();
return TRUE;
}
out_result->code = (uint64_t)signum;
out_result->exception_address = (uint64_t)caughtExceptionAddress;
out_result->instruction_pointer = caughtInstructionPointer;
caughtExceptionAddress = 0;
caughtInstructionPointer = 0;
removeExceptionHandler();
return FALSE;
}