Line | Branch | Exec | Source |
---|---|---|---|
1 | /* GATE PROJECT LICENSE: | ||
2 | +----------------------------------------------------------------------------+ | ||
3 | | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> | | ||
4 | | All rights reserved. | | ||
5 | | | | ||
6 | | Redistribution and use in source and binary forms, with or without | | ||
7 | | modification, are permitted provided that the following conditions are met:| | ||
8 | | | | ||
9 | | 1. Redistributions of source code must retain the above copyright notice, | | ||
10 | | this list of conditions and the following disclaimer. | | ||
11 | | 2. Redistributions in binary form must reproduce the above copyright | | ||
12 | | notice, this list of conditions and the following disclaimer in the | | ||
13 | | documentation and/or other materials provided with the distribution. | | ||
14 | | | | ||
15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| | ||
16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | ||
17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ||
18 | | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | | ||
19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | ||
20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | ||
21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | ||
22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | ||
23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | ||
24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | ||
25 | | THE POSSIBILITY OF SUCH DAMAGE. | | ||
26 | +----------------------------------------------------------------------------+ | ||
27 | */ | ||
28 | #include "gate/functions.h" | ||
29 | #include "gate/results.h" | ||
30 | #include "gate/memalloc.h" | ||
31 | #include "gate/callstacks.h" | ||
32 | #include "gate/debugging.h" | ||
33 | |||
34 | #if defined(GATE_COMPILER_MSVC) | ||
35 | # if defined(GATE_SYS_EFI) | ||
36 | # define GATE_FUNCTION_GUARD_NOGUARD 1 | ||
37 | # else | ||
38 | # define GATE_FUNCTION_GUARD_WINSEH 1 | ||
39 | # endif | ||
40 | #else | ||
41 | # define GATE_FUNCTION_GUARD_SIGNALS 1 | ||
42 | #endif | ||
43 | |||
44 | #define GATE_FUNCTIONS_GENERIC_IMPL 1 | ||
45 | |||
46 | #if defined(GATE_FUNCTIONS_GENERIC_IMPL) | ||
47 | |||
48 | #if defined(GATE_COMPILER_WATCOM) | ||
49 | typedef short fparam_t; | ||
50 | #else | ||
51 | typedef void* fparam_t; | ||
52 | #endif | ||
53 | |||
54 | typedef gate_uint64_t(*gate_function_generic_t)( | ||
55 | fparam_t a000, fparam_t a001, fparam_t a002, fparam_t a003, fparam_t a004, fparam_t a005, fparam_t a006, fparam_t a007, fparam_t a008, fparam_t a009, | ||
56 | fparam_t a010, fparam_t a011, fparam_t a012, fparam_t a013, fparam_t a014, fparam_t a015, fparam_t a016, fparam_t a017, fparam_t a018, fparam_t a019, | ||
57 | fparam_t a020, fparam_t a021, fparam_t a022, fparam_t a023, fparam_t a024, fparam_t a025, fparam_t a026, fparam_t a027, fparam_t a028, fparam_t a029, | ||
58 | fparam_t a030, fparam_t a031, fparam_t a032, fparam_t a033, fparam_t a034, fparam_t a035, fparam_t a036, fparam_t a037, fparam_t a038, fparam_t a039, | ||
59 | fparam_t a040, fparam_t a041, fparam_t a042, fparam_t a043, fparam_t a044, fparam_t a045, fparam_t a046, fparam_t a047, fparam_t a048, fparam_t a049, | ||
60 | fparam_t a050, fparam_t a051, fparam_t a052, fparam_t a053, fparam_t a054, fparam_t a055, fparam_t a056, fparam_t a057, fparam_t a058, fparam_t a059, | ||
61 | fparam_t a060, fparam_t a061, fparam_t a062, fparam_t a063 | ||
62 | ); | ||
63 | |||
64 | #define REGISTER_TYPE_CONVERTER(type, arg_type_name) \ | ||
65 | typedef union { \ | ||
66 | type native_value; \ | ||
67 | fparam_t generic_value[(sizeof(fparam_t) + sizeof(type) - 1) / sizeof(fparam_t)]; \ | ||
68 | } arg_type_name ## _converter_t | ||
69 | |||
70 | REGISTER_TYPE_CONVERTER(unsigned char, unsigned_char); | ||
71 | REGISTER_TYPE_CONVERTER(signed char, signed_char); | ||
72 | REGISTER_TYPE_CONVERTER(unsigned short, unsigned_short); | ||
73 | REGISTER_TYPE_CONVERTER(signed short, signed_short); | ||
74 | REGISTER_TYPE_CONVERTER(unsigned int, unsigned_int); | ||
75 | REGISTER_TYPE_CONVERTER(signed int, signed_int); | ||
76 | REGISTER_TYPE_CONVERTER(unsigned long, unsigned_long); | ||
77 | REGISTER_TYPE_CONVERTER(signed long, signed_long); | ||
78 | REGISTER_TYPE_CONVERTER(gate_uint64_t, unsigned_longlong); | ||
79 | REGISTER_TYPE_CONVERTER(gate_int64_t, signed_longlong); | ||
80 | REGISTER_TYPE_CONVERTER(float, float); | ||
81 | REGISTER_TYPE_CONVERTER(double, double); | ||
82 | REGISTER_TYPE_CONVERTER(long double, longdouble); | ||
83 | REGISTER_TYPE_CONVERTER(void*, pointer); | ||
84 | |||
85 | #define CONVERT_TYPE_TO_GENERIC(arg_type_name, input_value, output_ptr, output_count, output_max) do { \ | ||
86 | arg_type_name ## _converter_t converter = GATE_INIT_EMPTY; \ | ||
87 | if(sizeof(input_value) > (sizeof(fparam_t) * output_max)) \ | ||
88 | { \ | ||
89 | *output_count = 0; \ | ||
90 | } \ | ||
91 | else \ | ||
92 | { \ | ||
93 | converter.native_value = input_value; \ | ||
94 | *output_count = sizeof(converter.generic_value) / sizeof(fparam_t); \ | ||
95 | gate_mem_copy(output_ptr, &converter.generic_value[0], sizeof(converter.generic_value)); \ | ||
96 | } \ | ||
97 | } while(0) | ||
98 | |||
99 | #if defined(GATE_SYS_WIN) | ||
100 | #else | ||
101 | # define GATE_FUNCTION_ARGS_MAX_ALIGNMENT | ||
102 | #endif | ||
103 | |||
104 | 15 | static unsigned gate_function_load_argument(gate_function_argument_t* arg, fparam_t* target, unsigned target_count) | |
105 | { | ||
106 | 15 | unsigned target_used = 0; | |
107 | |||
108 |
3/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
|
15 | if (!arg || !target || (target_count == 0)) |
109 | { | ||
110 | ✗ | return 0; | |
111 | } | ||
112 | |||
113 |
10/16✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
15 | switch (arg->arg_type) |
114 | { | ||
115 | 2 | case GATE_FUNCTION_ARG_UCHAR: | |
116 | { | ||
117 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | CONVERT_TYPE_TO_GENERIC(unsigned_char, arg->arg_value.u_chr, target, &target_used, target_count); |
118 | 2 | break; | |
119 | } | ||
120 | ✗ | case GATE_FUNCTION_ARG_SCHAR: | |
121 | { | ||
122 | ✗ | CONVERT_TYPE_TO_GENERIC(signed_char, arg->arg_value.s_chr, target, &target_used, target_count); | |
123 | ✗ | break; | |
124 | } | ||
125 | 2 | case GATE_FUNCTION_ARG_USHORT: | |
126 | { | ||
127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | CONVERT_TYPE_TO_GENERIC(unsigned_short, arg->arg_value.u_short, target, &target_used, target_count); |
128 | 2 | break; | |
129 | } | ||
130 | 1 | case GATE_FUNCTION_ARG_SSHORT: | |
131 | { | ||
132 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | CONVERT_TYPE_TO_GENERIC(signed_short, arg->arg_value.s_short, target, &target_used, target_count); |
133 | 1 | break; | |
134 | } | ||
135 | 1 | case GATE_FUNCTION_ARG_UINT: | |
136 | { | ||
137 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | CONVERT_TYPE_TO_GENERIC(unsigned_int, arg->arg_value.u_int, target, &target_used, target_count); |
138 | 1 | break; | |
139 | } | ||
140 | 2 | case GATE_FUNCTION_ARG_SINT: | |
141 | { | ||
142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | CONVERT_TYPE_TO_GENERIC(signed_int, arg->arg_value.s_int, target, &target_used, target_count); |
143 | 2 | break; | |
144 | } | ||
145 | 2 | case GATE_FUNCTION_ARG_ULONG: | |
146 | { | ||
147 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | CONVERT_TYPE_TO_GENERIC(unsigned_long, arg->arg_value.u_long, target, &target_used, target_count); |
148 | 2 | break; | |
149 | } | ||
150 | 1 | case GATE_FUNCTION_ARG_SLONG: | |
151 | { | ||
152 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | CONVERT_TYPE_TO_GENERIC(signed_long, arg->arg_value.s_long, target, &target_used, target_count); |
153 | 1 | break; | |
154 | } | ||
155 | 2 | case GATE_FUNCTION_ARG_ULONGLONG: | |
156 | { | ||
157 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | CONVERT_TYPE_TO_GENERIC(unsigned_longlong, arg->arg_value.u_long_long, target, &target_used, target_count); |
158 | 2 | break; | |
159 | } | ||
160 | 1 | case GATE_FUNCTION_ARG_SLONGLONG: | |
161 | { | ||
162 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | CONVERT_TYPE_TO_GENERIC(signed_longlong, arg->arg_value.s_long_long, target, &target_used, target_count); |
163 | 1 | break; | |
164 | } | ||
165 | ✗ | case GATE_FUNCTION_ARG_FLOAT: | |
166 | { | ||
167 | ✗ | CONVERT_TYPE_TO_GENERIC(float, arg->arg_value.flt, target, &target_used, target_count); | |
168 | ✗ | break; | |
169 | } | ||
170 | ✗ | case GATE_FUNCTION_ARG_DOUBLE: | |
171 | { | ||
172 | ✗ | CONVERT_TYPE_TO_GENERIC(double, arg->arg_value.dbl, target, &target_used, target_count); | |
173 | ✗ | break; | |
174 | } | ||
175 | ✗ | case GATE_FUNCTION_ARG_LONGDOUBLE: | |
176 | { | ||
177 | ✗ | CONVERT_TYPE_TO_GENERIC(longdouble, arg->arg_value.ldbl, target, &target_used, target_count); | |
178 | ✗ | break; | |
179 | } | ||
180 | 1 | case GATE_FUNCTION_ARG_POINTER: | |
181 | { | ||
182 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | CONVERT_TYPE_TO_GENERIC(pointer, arg->arg_value.ptr, target, &target_used, target_count); |
183 | 1 | break; | |
184 | } | ||
185 | ✗ | case GATE_FUNCTION_ARG_BLOB: | |
186 | { | ||
187 | ✗ | CONVERT_TYPE_TO_GENERIC(unsigned_char, arg->arg_value.u_chr, target, &target_used, target_count); | |
188 | ✗ | break; | |
189 | } | ||
190 | } | ||
191 | 15 | return target_used; | |
192 | } | ||
193 | |||
194 | 3 | gate_result_t gate_function_invoke_generic(gate_funcptr_t func_ptr, gate_enumint_t flags, | |
195 | gate_function_argument_t* args, gate_size_t arg_count, | ||
196 | gate_function_argument_t* retval) | ||
197 | { | ||
198 | 3 | fparam_t v[64] = GATE_INIT_EMPTY; | |
199 | 3 | gate_uint64_t r = 0; | |
200 | 3 | gate_function_generic_t func = (gate_function_generic_t)func_ptr; | |
201 | 3 | unsigned count = sizeof(v) / sizeof(v[0]); | |
202 | unsigned used, n; | ||
203 | fparam_t tmp[16]; | ||
204 | 3 | fparam_t* ptr_v = &v[0]; | |
205 | |||
206 | GATE_UNUSED_ARG(flags); | ||
207 | |||
208 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
|
18 | while (arg_count-- != 0) |
209 | { | ||
210 | 15 | gate_mem_clear(tmp, sizeof(tmp)); | |
211 | 15 | used = gate_function_load_argument(args, tmp, sizeof(tmp) / sizeof(tmp[0])); | |
212 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (used > count) |
213 | { | ||
214 | ✗ | return GATE_RESULT_OUTOFMEMORY; | |
215 | } | ||
216 | #if defined(GATE_FUNCTION_ARGS_MAX_ALIGNMENT) | ||
217 | /* type was greater than pointer, add padding words to extend alignment */ | ||
218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (used > 1) |
219 | { | ||
220 | unsigned mod, padd; | ||
221 | ✗ | mod = count % used; | |
222 | ✗ | if (mod > 0) | |
223 | { | ||
224 | ✗ | padd = used - mod; | |
225 | ✗ | if (padd > count) | |
226 | { | ||
227 | ✗ | return GATE_RESULT_OUTOFMEMORY; | |
228 | } | ||
229 | ✗ | for (n = 0; n != padd; ++n) | |
230 | { | ||
231 | ✗ | ptr_v[n] = ((fparam_t)0); | |
232 | } | ||
233 | ✗ | ptr_v += padd; | |
234 | ✗ | count -= padd; | |
235 | } | ||
236 | } | ||
237 | #else | ||
238 | /* we are pointer-aligned -> nothing to do */ | ||
239 | #endif | ||
240 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | for (n = 0; n != used; ++n) |
241 | { | ||
242 | 15 | ptr_v[n] = tmp[n]; | |
243 | } | ||
244 | 15 | ptr_v += used; | |
245 | 15 | count -= used; | |
246 | 15 | ++args; | |
247 | } | ||
248 | |||
249 | 3 | r = func( | |
250 | v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], | ||
251 | v[10], v[11], v[12], v[13], v[14], v[15], v[16], v[17], v[18], v[19], | ||
252 | v[20], v[21], v[22], v[23], v[24], v[25], v[26], v[27], v[28], v[29], | ||
253 | v[30], v[31], v[32], v[33], v[34], v[35], v[36], v[37], v[38], v[39], | ||
254 | v[40], v[41], v[42], v[43], v[44], v[45], v[46], v[47], v[48], v[49], | ||
255 | v[50], v[51], v[52], v[53], v[54], v[55], v[56], v[57], v[58], v[59], | ||
256 | v[60], v[61], v[62], v[63] | ||
257 | ); | ||
258 | |||
259 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (retval) |
260 | { | ||
261 | 3 | retval->arg_value.u_long_long = r; | |
262 | 3 | retval->arg_type = GATE_FUNCTION_ARG_ULONGLONG; | |
263 | } | ||
264 | |||
265 | 3 | return GATE_RESULT_OK; | |
266 | } | ||
267 | |||
268 | #endif | ||
269 | |||
270 | |||
271 | #if defined(GATE_FUNCTIONS_X86_IMPL) | ||
272 | |||
273 | typedef struct gate_function_context | ||
274 | { | ||
275 | void* function_ptr; | ||
276 | int eax; | ||
277 | int ebx; | ||
278 | int ecx; | ||
279 | int edx; | ||
280 | int esi; | ||
281 | int edi; | ||
282 | |||
283 | gate_function_argument_t arguments[32]; | ||
284 | gate_size_t argumentcount; | ||
285 | |||
286 | } gate_function_context_t; | ||
287 | |||
288 | typedef union x86_arguments | ||
289 | { | ||
290 | void* function_ptr; | ||
291 | unsigned char buffer[1024]; | ||
292 | } x86_arguments_t; | ||
293 | |||
294 | typedef gate_uint64_t(*x86_c_func_t)(x86_arguments_t args); | ||
295 | |||
296 | gate_result_t gate_function_invoke_generic(void* func_ptr, gate_enumint_t flags, | ||
297 | gate_function_argument_t* args, gate_size_t arg_count, gate_function_argument_t* retval) | ||
298 | { | ||
299 | gate_result_t ret = GATE_RESULT_OK; | ||
300 | x86_c_func_t func = (x86_c_func_t)func_ptr; | ||
301 | gate_uint64_t x86_ret = NULL; | ||
302 | x86_arguments_t x86_args = GATE_INIT_EMPTY; | ||
303 | gate_size_t n; | ||
304 | |||
305 | for (n = 0; n != sizeof(x86_args.buffer); ++n) | ||
306 | { | ||
307 | x86_args.buffer[n] = (unsigned char)(n % 256); | ||
308 | } | ||
309 | |||
310 | x86_ret = func(x86_args); | ||
311 | if (retval) | ||
312 | { | ||
313 | retval->arg_value.u_long_long = x86_ret; | ||
314 | retval->arg_type = GATE_FUNCTION_ARG_ULONGLONG; | ||
315 | } | ||
316 | return ret; | ||
317 | } | ||
318 | |||
319 | |||
320 | #endif /* GATE_FUNCTIONS_X86_IMPL */ | ||
321 | |||
322 | #if defined(GATE_FUNCTIONS_X86X64_IMPL) | ||
323 | |||
324 | |||
325 | typedef union x64_arguments | ||
326 | { | ||
327 | void* function_ptr[1024 / sizeof(void*)]; | ||
328 | unsigned char buffer[1024]; | ||
329 | } x64_arguments_t; | ||
330 | |||
331 | typedef void* (*x64_c_func_t)( | ||
332 | void* a1, void* a2, void* a3, void* a4, void* a5, void* a6, void* a7, void* a8, | ||
333 | void* b1, void* b2, void* b3, void* b4, void* b5, void* b6, void* b7, void* b8, | ||
334 | void* c1, void* c2, void* c3, void* c4, void* c5, void* c6, void* c7, void* c8, | ||
335 | void* d1, void* d2, void* d3, void* d4, void* d5, void* d6, void* d7, void* d8, | ||
336 | void* e1, void* e2, void* e3, void* e4, void* e5, void* e6, void* e7, void* e8, | ||
337 | void* f1, void* f2, void* f3, void* f4, void* f5, void* f6, void* f7, void* f8 | ||
338 | ); | ||
339 | |||
340 | gate_result_t gate_function_invoke_generic(void* func_ptr, gate_enumint_t flags, | ||
341 | gate_function_argument_t* args, gate_size_t arg_count, gate_function_argument_t* retval) | ||
342 | { | ||
343 | gate_result_t ret = GATE_RESULT_OK; | ||
344 | x64_c_func_t func = (x64_c_func_t)func_ptr; | ||
345 | void* x64_ret = NULL; | ||
346 | x64_arguments_t x64_args = GATE_INIT_EMPTY; | ||
347 | gate_size_t n, i; | ||
348 | void* a[8]; | ||
349 | void* b[8]; | ||
350 | void* c[8]; | ||
351 | void* d[8]; | ||
352 | void* e[8]; | ||
353 | void* f[8]; | ||
354 | |||
355 | i = 0; | ||
356 | for (n = 0; n != 8; ++n) a[n] = (unsigned char)(i++ % 256); | ||
357 | for (n = 0; n != 8; ++n) b[n] = (unsigned char)(i++ % 256); | ||
358 | for (n = 0; n != 8; ++n) c[n] = (unsigned char)(i++ % 256); | ||
359 | for (n = 0; n != 8; ++n) d[n] = (unsigned char)(i++ % 256); | ||
360 | for (n = 0; n != 8; ++n) e[n] = (unsigned char)(i++ % 256); | ||
361 | for (n = 0; n != 8; ++n) f[n] = (unsigned char)(i++ % 256); | ||
362 | |||
363 | x64_ret = func( | ||
364 | a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], | ||
365 | b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], | ||
366 | c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], | ||
367 | d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], | ||
368 | e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], | ||
369 | f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7] | ||
370 | ); | ||
371 | if (retval) | ||
372 | { | ||
373 | retval->arg_value.u_long_long = x64_ret; | ||
374 | retval->arg_type = GATE_FUNCTION_ARG_ULONGLONG; | ||
375 | } | ||
376 | |||
377 | return ret; | ||
378 | } | ||
379 | |||
380 | #endif /* GATE_FUNCTIONS_X86X64_IMPL */ | ||
381 | |||
382 | |||
383 | |||
384 | #if defined(GATE_FUNCTION_GUARD_WINSEH) | ||
385 | |||
386 | #include "gate/platforms.h" | ||
387 | |||
388 | static int gate_win32_seh_filter(unsigned int seh_code, | ||
389 | struct _EXCEPTION_POINTERS* xcpt_ptrs, | ||
390 | gate_function_fault_handler_t handler, void* param) | ||
391 | { | ||
392 | unsigned fault_code; | ||
393 | gate_result_t result; | ||
394 | |||
395 | GATE_UNUSED_ARG(xcpt_ptrs); | ||
396 | |||
397 | switch (seh_code) | ||
398 | { | ||
399 | case EXCEPTION_FLT_DENORMAL_OPERAND: | ||
400 | case EXCEPTION_FLT_DIVIDE_BY_ZERO: | ||
401 | case EXCEPTION_FLT_INEXACT_RESULT: | ||
402 | case EXCEPTION_FLT_INVALID_OPERATION: | ||
403 | case EXCEPTION_FLT_OVERFLOW: | ||
404 | case EXCEPTION_FLT_STACK_CHECK: | ||
405 | case EXCEPTION_FLT_UNDERFLOW: | ||
406 | fault_code = GATE_FUNCTION_FAULT_FLOAT; | ||
407 | break; | ||
408 | case EXCEPTION_ACCESS_VIOLATION: | ||
409 | case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: | ||
410 | case EXCEPTION_GUARD_PAGE: | ||
411 | case EXCEPTION_IN_PAGE_ERROR: | ||
412 | fault_code = GATE_FUNCTION_FAULT_ADDRESS; | ||
413 | break; | ||
414 | case EXCEPTION_ILLEGAL_INSTRUCTION: | ||
415 | fault_code = GATE_FUNCTION_FAULT_INSTRUCTION; | ||
416 | break; | ||
417 | case EXCEPTION_SINGLE_STEP: | ||
418 | case EXCEPTION_BREAKPOINT: | ||
419 | fault_code = GATE_FUNCTION_FAULT_BREAKPOINT; | ||
420 | break; | ||
421 | case EXCEPTION_DATATYPE_MISALIGNMENT: | ||
422 | fault_code = GATE_FUNCTION_FAULT_ALIGNMENT; | ||
423 | break; | ||
424 | case EXCEPTION_INT_DIVIDE_BY_ZERO: | ||
425 | fault_code = GATE_FUNCTION_FAULT_ARITHMETIC; | ||
426 | break; | ||
427 | case EXCEPTION_INT_OVERFLOW: | ||
428 | fault_code = GATE_FUNCTION_FAULT_OVERFLOW; | ||
429 | break; | ||
430 | case EXCEPTION_INVALID_HANDLE: | ||
431 | fault_code = GATE_FUNCTION_FAULT_SYSTEM; | ||
432 | break; | ||
433 | case EXCEPTION_PRIV_INSTRUCTION: | ||
434 | fault_code = GATE_FUNCTION_FAULT_PRIVILEGE; | ||
435 | break; | ||
436 | case EXCEPTION_STACK_OVERFLOW: | ||
437 | fault_code = GATE_FUNCTION_FAULT_STACK; | ||
438 | break; | ||
439 | case EXCEPTION_NONCONTINUABLE_EXCEPTION: | ||
440 | case EXCEPTION_INVALID_DISPOSITION: | ||
441 | default: | ||
442 | fault_code = GATE_FUNCTION_FAULT_UNKNOWN; | ||
443 | break; | ||
444 | } | ||
445 | |||
446 | if (handler) | ||
447 | { | ||
448 | result = handler(fault_code, param); | ||
449 | if (GATE_FAILED(result)) | ||
450 | { | ||
451 | return EXCEPTION_CONTINUE_SEARCH; | ||
452 | } | ||
453 | } | ||
454 | return EXCEPTION_EXECUTE_HANDLER; | ||
455 | } | ||
456 | |||
457 | |||
458 | gate_result_t gate_function_invoke_guarded(gate_entrypoint_t entry_point, void* entry_param, | ||
459 | gate_function_fault_handler_t fault_handler, void* fault_param) | ||
460 | { | ||
461 | gate_result_t result = GATE_RESULT_OK; | ||
462 | __try | ||
463 | { | ||
464 | if (entry_point) | ||
465 | { | ||
466 | result = entry_point(entry_param); | ||
467 | } | ||
468 | } | ||
469 | __except (gate_win32_seh_filter(GetExceptionCode(), GetExceptionInformation(), fault_handler, fault_param)) | ||
470 | { | ||
471 | result = GATE_RESULT_BADINSTRUCTION; | ||
472 | } | ||
473 | return result; | ||
474 | } | ||
475 | |||
476 | #endif /* GATE_FUNCTION_GUARD_WINSEH */ | ||
477 | |||
478 | |||
479 | |||
480 | #if defined(GATE_FUNCTION_GUARD_SIGNALS) | ||
481 | |||
482 | #include "gate/atomics.h" | ||
483 | #include "gate/platforms.h" | ||
484 | #include "gate/callstacks.h" | ||
485 | #include "gate/threading.h" | ||
486 | #include <setjmp.h> | ||
487 | #include <signal.h> | ||
488 | |||
489 | |||
490 | static gate_thread_storage_t global_function_guard_registry; | ||
491 | static gate_atomic_flag_t global_function_guard_registry_initialized = GATE_ATOMIC_FLAG_INIT; | ||
492 | |||
493 | typedef struct gate_function_anchor_class | ||
494 | { | ||
495 | gate_callstack_jmpbuf_t context; | ||
496 | gate_function_fault_handler_t fault_handler; | ||
497 | void* fault_param; | ||
498 | } gate_function_anchor_t; | ||
499 | |||
500 | |||
501 | static void gate_function_guard_signal_handler(int signum); | ||
502 | |||
503 | 3 | static gate_result_t gate_function_guard_init() | |
504 | { | ||
505 | 3 | gate_result_t ret = GATE_RESULT_OK; | |
506 | |||
507 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
|
3 | if (false == gate_atomic_flag_set(&global_function_guard_registry_initialized)) |
508 | { | ||
509 | 1 | ret = gate_thread_storage_alloc(&global_function_guard_registry); | |
510 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (GATE_FAILED(ret)) |
511 | { | ||
512 | ✗ | gate_atomic_flag_clear(&global_function_guard_registry_initialized); | |
513 | ✗ | return ret; | |
514 | } | ||
515 | } | ||
516 | |||
517 | 3 | gate_platform_set_signal_handler(SIGABRT, &gate_function_guard_signal_handler, NULL); | |
518 | #ifdef SIGBUS | ||
519 | 3 | gate_platform_set_signal_handler(SIGBUS, &gate_function_guard_signal_handler, NULL); | |
520 | #endif | ||
521 | 3 | gate_platform_set_signal_handler(SIGFPE, &gate_function_guard_signal_handler, NULL); | |
522 | 3 | gate_platform_set_signal_handler(SIGILL, &gate_function_guard_signal_handler, NULL); | |
523 | 3 | gate_platform_set_signal_handler(SIGSEGV, &gate_function_guard_signal_handler, NULL); | |
524 | #ifdef SIGSYS | ||
525 | 3 | gate_platform_set_signal_handler(SIGSYS, &gate_function_guard_signal_handler, NULL); | |
526 | #endif | ||
527 | #ifdef SIGTRAP | ||
528 | 3 | gate_platform_set_signal_handler(SIGTRAP, &gate_function_guard_signal_handler, NULL); | |
529 | #endif | ||
530 | 3 | return ret; | |
531 | } | ||
532 | |||
533 | ✗ | static unsigned translate_signal(int sig) | |
534 | { | ||
535 | ✗ | switch (sig) | |
536 | { | ||
537 | ✗ | case SIGSEGV: return GATE_FUNCTION_FAULT_ADDRESS; | |
538 | #ifdef SIGBUS | ||
539 | ✗ | case SIGBUS: return GATE_FUNCTION_FAULT_ADDRESS; | |
540 | #endif | ||
541 | ✗ | case SIGABRT: return GATE_FUNCTION_FAULT_ADDRESS; | |
542 | |||
543 | ✗ | case SIGILL: return GATE_FUNCTION_FAULT_INSTRUCTION; | |
544 | ✗ | case SIGFPE: return GATE_FUNCTION_FAULT_ARITHMETIC; | |
545 | |||
546 | #ifdef SIGSYS | ||
547 | ✗ | case SIGSYS: return GATE_FUNCTION_FAULT_SYSTEM; | |
548 | #endif | ||
549 | #ifdef SIGTRAP | ||
550 | ✗ | case SIGTRAP: return GATE_FUNCTION_FAULT_BREAKPOINT; | |
551 | #endif | ||
552 | } | ||
553 | ✗ | return GATE_FUNCTION_FAULT_UNKNOWN; | |
554 | } | ||
555 | |||
556 | ✗ | static void gate_function_guard_signal_handler(int signum) | |
557 | { | ||
558 | gate_result_t result; | ||
559 | ✗ | gate_function_anchor_t* ptr_anchor = NULL; | |
560 | unsigned fault_code; | ||
561 | |||
562 | ✗ | result = gate_thread_storage_get(&global_function_guard_registry, (void**)&ptr_anchor); | |
563 | ✗ | if (GATE_SUCCEEDED(result) && (ptr_anchor != NULL)) | |
564 | { | ||
565 | ✗ | fault_code = translate_signal(signum); | |
566 | ✗ | result = ptr_anchor->fault_handler(fault_code, ptr_anchor->fault_param); | |
567 | ✗ | if (GATE_SUCCEEDED(result)) | |
568 | { | ||
569 | ✗ | gate_callstack_jump(&ptr_anchor->context); | |
570 | } | ||
571 | } | ||
572 | ✗ | } | |
573 | |||
574 | ✗ | static gate_result_t gate_function_guard_error_branch(void* param) | |
575 | { | ||
576 | (void)param; | ||
577 | ✗ | return GATE_RESULT_BADINSTRUCTION; | |
578 | } | ||
579 | |||
580 | 3 | gate_result_t gate_function_invoke_guarded(gate_entrypoint_t entry_point, void* entry_param, | |
581 | gate_function_fault_handler_t fault_handler, void* fault_param) | ||
582 | { | ||
583 | 3 | volatile gate_result_t ret = GATE_RESULT_FAILED; | |
584 | gate_function_anchor_t new_anchor; | ||
585 | 3 | gate_function_anchor_t* ptr_old_anchor = NULL; | |
586 | |||
587 | 3 | ret = gate_function_guard_init(); | |
588 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (GATE_FAILED(ret)) |
589 | { | ||
590 | ✗ | return ret; | |
591 | } | ||
592 | |||
593 | 3 | gate_thread_storage_get(&global_function_guard_registry, (void**)&ptr_old_anchor); | |
594 | 3 | new_anchor.fault_handler = fault_handler; | |
595 | 3 | new_anchor.fault_param = fault_param; | |
596 | |||
597 | 3 | ret = gate_thread_storage_set(&global_function_guard_registry, &new_anchor); | |
598 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (GATE_FAILED(ret)) |
599 | { | ||
600 | ✗ | return ret; | |
601 | } | ||
602 | |||
603 | 3 | ret = gate_callstack_fork(&new_anchor.context, entry_point, entry_param, &gate_function_guard_error_branch, NULL); | |
604 | |||
605 | 3 | gate_thread_storage_set(&global_function_guard_registry, ptr_old_anchor); | |
606 | 3 | return ret; | |
607 | } | ||
608 | |||
609 | #endif /* GATE_FUNCTION_GUARD_SIGNALS */ | ||
610 | |||
611 | #if defined(GATE_FUNCTION_GUARD_NOGUARD) | ||
612 | |||
613 | gate_result_t gate_function_invoke_guarded(gate_entrypoint_t entry_point, void* entry_param, | ||
614 | gate_function_fault_handler_t fault_handler, void* fault_param) | ||
615 | { | ||
616 | gate_result_t ret; | ||
617 | |||
618 | ret = entry_point(entry_param); | ||
619 | return ret; | ||
620 | } | ||
621 | |||
622 | #endif /* GATE_FUNCTION_GUARD_NOGUARD */ | ||
623 | |||
624 |