GCC Code Coverage Report


Directory: src/gate/
File: src/gate/functions.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 82 133 61.7%
Functions: 4 7 57.1%
Branches: 35 90 38.9%

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