GCC Code Coverage Report


Directory: src/gate/
File: src/gate/functions.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 85 133 63.9%
Functions: 4 7 57.1%
Branches: 37 90 41.1%

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
11/16
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 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 1 case GATE_FUNCTION_ARG_SCHAR:
121 {
122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 CONVERT_TYPE_TO_GENERIC(signed_char, arg->arg_value.s_chr, target, &target_used, target_count);
123 1 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 1 case GATE_FUNCTION_ARG_SINT:
141 {
142
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 CONVERT_TYPE_TO_GENERIC(signed_int, arg->arg_value.s_int, target, &target_used, target_count);
143 1 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 fparam_t* ptr_v = &v[0];
200 3 unsigned count = sizeof(v) / sizeof(v[0]);
201 3 gate_uint64_t r = 0;
202 3 gate_function_generic_t func = (gate_function_generic_t)func_ptr;
203
204 GATE_UNUSED_ARG(flags);
205
206
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 while (arg_count-- != 0)
207 {
208 unsigned used, n;
209 fparam_t tmp[16];
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;
221 mod = count % used;
222 if (mod > 0)
223 {
224 unsigned 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 union x86_arguments
274 {
275 void* function_ptr;
276 unsigned char buffer[1024];
277 } x86_arguments_t;
278
279 typedef gate_uint64_t(*x86_c_func_t)(x86_arguments_t args);
280
281 gate_result_t gate_function_invoke_generic(void* func_ptr, gate_enumint_t flags,
282 gate_function_argument_t* args, gate_size_t arg_count, gate_function_argument_t* retval)
283 {
284 gate_result_t ret = GATE_RESULT_OK;
285 x86_c_func_t func = (x86_c_func_t)func_ptr;
286 gate_uint64_t x86_ret = NULL;
287 x86_arguments_t x86_args = GATE_INIT_EMPTY;
288 gate_size_t n;
289
290 for (n = 0; n != sizeof(x86_args.buffer); ++n)
291 {
292 x86_args.buffer[n] = (unsigned char)(n % 256);
293 }
294
295 x86_ret = func(x86_args);
296 if (retval)
297 {
298 retval->arg_value.u_long_long = x86_ret;
299 retval->arg_type = GATE_FUNCTION_ARG_ULONGLONG;
300 }
301 return ret;
302 }
303
304
305 #endif /* GATE_FUNCTIONS_X86_IMPL */
306
307 #if defined(GATE_FUNCTIONS_X86X64_IMPL)
308
309 typedef void* (*x64_c_func_t)(
310 void* a1, void* a2, void* a3, void* a4, void* a5, void* a6, void* a7, void* a8,
311 void* b1, void* b2, void* b3, void* b4, void* b5, void* b6, void* b7, void* b8,
312 void* c1, void* c2, void* c3, void* c4, void* c5, void* c6, void* c7, void* c8,
313 void* d1, void* d2, void* d3, void* d4, void* d5, void* d6, void* d7, void* d8,
314 void* e1, void* e2, void* e3, void* e4, void* e5, void* e6, void* e7, void* e8,
315 void* f1, void* f2, void* f3, void* f4, void* f5, void* f6, void* f7, void* f8
316 );
317
318 gate_result_t gate_function_invoke_generic(void* func_ptr, gate_enumint_t flags,
319 gate_function_argument_t* args, gate_size_t arg_count, gate_function_argument_t* retval)
320 {
321 gate_result_t ret = GATE_RESULT_OK;
322 x64_c_func_t func = (x64_c_func_t)func_ptr;
323 void* x64_ret = NULL;
324 gate_size_t n, i;
325 void* a[8];
326 void* b[8];
327 void* c[8];
328 void* d[8];
329 void* e[8];
330 void* f[8];
331
332 i = 0;
333 for (n = 0; n != 8; ++n) a[n] = (unsigned char)(i++ % 256);
334 for (n = 0; n != 8; ++n) b[n] = (unsigned char)(i++ % 256);
335 for (n = 0; n != 8; ++n) c[n] = (unsigned char)(i++ % 256);
336 for (n = 0; n != 8; ++n) d[n] = (unsigned char)(i++ % 256);
337 for (n = 0; n != 8; ++n) e[n] = (unsigned char)(i++ % 256);
338 for (n = 0; n != 8; ++n) f[n] = (unsigned char)(i++ % 256);
339
340 x64_ret = func(
341 a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
342 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
343 c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7],
344 d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
345 e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7],
346 f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]
347 );
348 if (retval)
349 {
350 retval->arg_value.u_long_long = x64_ret;
351 retval->arg_type = GATE_FUNCTION_ARG_ULONGLONG;
352 }
353
354 return ret;
355 }
356
357 #endif /* GATE_FUNCTIONS_X86X64_IMPL */
358
359
360
361 #if defined(GATE_FUNCTION_GUARD_WINSEH)
362
363 #include "gate/platforms.h"
364
365 static int gate_win32_seh_filter(unsigned int seh_code,
366 struct _EXCEPTION_POINTERS* xcpt_ptrs,
367 gate_function_fault_handler_t handler, void* param)
368 {
369 unsigned fault_code;
370 gate_result_t result;
371
372 GATE_UNUSED_ARG(xcpt_ptrs);
373
374 switch (seh_code)
375 {
376 case EXCEPTION_FLT_DENORMAL_OPERAND:
377 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
378 case EXCEPTION_FLT_INEXACT_RESULT:
379 case EXCEPTION_FLT_INVALID_OPERATION:
380 case EXCEPTION_FLT_OVERFLOW:
381 case EXCEPTION_FLT_STACK_CHECK:
382 case EXCEPTION_FLT_UNDERFLOW:
383 fault_code = GATE_FUNCTION_FAULT_FLOAT;
384 break;
385 case EXCEPTION_ACCESS_VIOLATION:
386 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
387 case EXCEPTION_GUARD_PAGE:
388 case EXCEPTION_IN_PAGE_ERROR:
389 fault_code = GATE_FUNCTION_FAULT_ADDRESS;
390 break;
391 case EXCEPTION_ILLEGAL_INSTRUCTION:
392 fault_code = GATE_FUNCTION_FAULT_INSTRUCTION;
393 break;
394 case EXCEPTION_SINGLE_STEP:
395 case EXCEPTION_BREAKPOINT:
396 fault_code = GATE_FUNCTION_FAULT_BREAKPOINT;
397 break;
398 case EXCEPTION_DATATYPE_MISALIGNMENT:
399 fault_code = GATE_FUNCTION_FAULT_ALIGNMENT;
400 break;
401 case EXCEPTION_INT_DIVIDE_BY_ZERO:
402 fault_code = GATE_FUNCTION_FAULT_ARITHMETIC;
403 break;
404 case EXCEPTION_INT_OVERFLOW:
405 fault_code = GATE_FUNCTION_FAULT_OVERFLOW;
406 break;
407 case EXCEPTION_INVALID_HANDLE:
408 fault_code = GATE_FUNCTION_FAULT_SYSTEM;
409 break;
410 case EXCEPTION_PRIV_INSTRUCTION:
411 fault_code = GATE_FUNCTION_FAULT_PRIVILEGE;
412 break;
413 case EXCEPTION_STACK_OVERFLOW:
414 fault_code = GATE_FUNCTION_FAULT_STACK;
415 break;
416 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
417 case EXCEPTION_INVALID_DISPOSITION:
418 default:
419 fault_code = GATE_FUNCTION_FAULT_UNKNOWN;
420 break;
421 }
422
423 if (handler)
424 {
425 result = handler(fault_code, param);
426 if (GATE_FAILED(result))
427 {
428 return EXCEPTION_CONTINUE_SEARCH;
429 }
430 }
431 return EXCEPTION_EXECUTE_HANDLER;
432 }
433
434
435 gate_result_t gate_function_invoke_guarded(gate_entrypoint_t entry_point, void* entry_param,
436 gate_function_fault_handler_t fault_handler, void* fault_param)
437 {
438 gate_result_t result = GATE_RESULT_OK;
439 __try
440 {
441 if (entry_point)
442 {
443 result = entry_point(entry_param);
444 }
445 }
446 __except (gate_win32_seh_filter(GetExceptionCode(), GetExceptionInformation(), fault_handler, fault_param))
447 {
448 result = GATE_RESULT_BADINSTRUCTION;
449 }
450 return result;
451 }
452
453 #endif /* GATE_FUNCTION_GUARD_WINSEH */
454
455
456
457 #if defined(GATE_FUNCTION_GUARD_SIGNALS)
458
459 #include "gate/atomics.h"
460 #include "gate/platforms.h"
461 #include "gate/callstacks.h"
462 #include "gate/threading.h"
463 #include <setjmp.h>
464 #include <signal.h>
465
466
467 static gate_thread_storage_t global_function_guard_registry;
468 static gate_atomic_flag_t global_function_guard_registry_initialized = GATE_ATOMIC_FLAG_INIT;
469
470 typedef struct gate_function_anchor_class
471 {
472 gate_callstack_jmpbuf_t context;
473 gate_function_fault_handler_t fault_handler;
474 void* fault_param;
475 } gate_function_anchor_t;
476
477
478 static void gate_function_guard_signal_handler(int signum);
479
480 3 static gate_result_t gate_function_guard_init()
481 {
482 3 gate_result_t ret = GATE_RESULT_OK;
483
484
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
3 if (false == gate_atomic_flag_set(&global_function_guard_registry_initialized))
485 {
486 1 ret = gate_thread_storage_alloc(&global_function_guard_registry);
487
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(ret))
488 {
489 gate_atomic_flag_clear(&global_function_guard_registry_initialized);
490 return ret;
491 }
492 }
493
494 3 gate_platform_set_signal_handler(SIGABRT, &gate_function_guard_signal_handler, NULL);
495 #ifdef SIGBUS
496 3 gate_platform_set_signal_handler(SIGBUS, &gate_function_guard_signal_handler, NULL);
497 #endif
498 3 gate_platform_set_signal_handler(SIGFPE, &gate_function_guard_signal_handler, NULL);
499 3 gate_platform_set_signal_handler(SIGILL, &gate_function_guard_signal_handler, NULL);
500 3 gate_platform_set_signal_handler(SIGSEGV, &gate_function_guard_signal_handler, NULL);
501 #ifdef SIGSYS
502 3 gate_platform_set_signal_handler(SIGSYS, &gate_function_guard_signal_handler, NULL);
503 #endif
504 #ifdef SIGTRAP
505 3 gate_platform_set_signal_handler(SIGTRAP, &gate_function_guard_signal_handler, NULL);
506 #endif
507 3 return ret;
508 }
509
510 static unsigned translate_signal(int sig)
511 {
512 switch (sig)
513 {
514 case SIGSEGV: return GATE_FUNCTION_FAULT_ADDRESS;
515 #ifdef SIGBUS
516 case SIGBUS: return GATE_FUNCTION_FAULT_ADDRESS;
517 #endif
518 case SIGABRT: return GATE_FUNCTION_FAULT_ADDRESS;
519
520 case SIGILL: return GATE_FUNCTION_FAULT_INSTRUCTION;
521 case SIGFPE: return GATE_FUNCTION_FAULT_ARITHMETIC;
522
523 #ifdef SIGSYS
524 case SIGSYS: return GATE_FUNCTION_FAULT_SYSTEM;
525 #endif
526 #ifdef SIGTRAP
527 case SIGTRAP: return GATE_FUNCTION_FAULT_BREAKPOINT;
528 #endif
529 }
530 return GATE_FUNCTION_FAULT_UNKNOWN;
531 }
532
533 static void gate_function_guard_signal_handler(int signum)
534 {
535 gate_function_anchor_t* ptr_anchor = NULL;
536 gate_result_t result = gate_thread_storage_get(&global_function_guard_registry, (void**)&ptr_anchor);
537 if (GATE_SUCCEEDED(result) && (ptr_anchor != NULL))
538 {
539 unsigned const fault_code = translate_signal(signum);
540 result = ptr_anchor->fault_handler(fault_code, ptr_anchor->fault_param);
541 if (GATE_SUCCEEDED(result))
542 {
543 gate_callstack_jump(&ptr_anchor->context);
544 }
545 }
546 }
547
548 static gate_result_t gate_function_guard_error_branch(void* param)
549 {
550 (void)param;
551 return GATE_RESULT_BADINSTRUCTION;
552 }
553
554 3 gate_result_t gate_function_invoke_guarded(gate_entrypoint_t entry_point, void* entry_param,
555 gate_function_fault_handler_t fault_handler, void* fault_param)
556 {
557 3 volatile gate_result_t ret = GATE_RESULT_FAILED;
558 gate_function_anchor_t new_anchor;
559 3 gate_function_anchor_t* ptr_old_anchor = NULL;
560
561 3 ret = gate_function_guard_init();
562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(ret))
563 {
564 return ret;
565 }
566
567 3 gate_thread_storage_get(&global_function_guard_registry, (void**)&ptr_old_anchor);
568 3 new_anchor.fault_handler = fault_handler;
569 3 new_anchor.fault_param = fault_param;
570
571 3 ret = gate_thread_storage_set(&global_function_guard_registry, &new_anchor);
572
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(ret))
573 {
574 return ret;
575 }
576
577 3 ret = gate_callstack_fork(&new_anchor.context, entry_point, entry_param, &gate_function_guard_error_branch, NULL);
578
579 3 gate_thread_storage_set(&global_function_guard_registry, ptr_old_anchor);
580 3 return ret;
581 }
582
583 #endif /* GATE_FUNCTION_GUARD_SIGNALS */
584
585 #if defined(GATE_FUNCTION_GUARD_NOGUARD)
586
587 gate_result_t gate_function_invoke_guarded(gate_entrypoint_t entry_point, void* entry_param,
588 gate_function_fault_handler_t fault_handler, void* fault_param)
589 {
590 gate_result_t ret;
591
592 ret = entry_point(entry_param);
593 return ret;
594 }
595
596 #endif /* GATE_FUNCTION_GUARD_NOGUARD */
597
598