GCC Code Coverage Report


Directory: src/gate/
File: src/gate/functions.c
Date: 2026-02-03 22:06:38
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-2026, 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 #elif defined(GATE_SYS_ARDUINO)
41 # define GATE_FUNCTION_GUARD_NOGUARD 1
42 #else
43 # define GATE_FUNCTION_GUARD_SIGNALS 1
44 #endif
45
46 #define GATE_FUNCTIONS_GENERIC_IMPL 1
47
48 #if defined(GATE_FUNCTIONS_GENERIC_IMPL)
49
50 #if defined(GATE_COMPILER_WATCOM)
51 typedef short fparam_t;
52 #else
53 typedef void* fparam_t;
54 #endif
55
56 typedef gate_uint64_t(*gate_function_generic_t)(
57 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,
58 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,
59 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,
60 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,
61 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,
62 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,
63 fparam_t a060, fparam_t a061, fparam_t a062, fparam_t a063
64 );
65
66 #define REGISTER_TYPE_CONVERTER(type, arg_type_name) \
67 typedef union { \
68 type native_value; \
69 fparam_t generic_value[(sizeof(fparam_t) + sizeof(type) - 1) / sizeof(fparam_t)]; \
70 } arg_type_name ## _converter_t
71
72 REGISTER_TYPE_CONVERTER(unsigned char, unsigned_char);
73 REGISTER_TYPE_CONVERTER(signed char, signed_char);
74 REGISTER_TYPE_CONVERTER(unsigned short, unsigned_short);
75 REGISTER_TYPE_CONVERTER(signed short, signed_short);
76 REGISTER_TYPE_CONVERTER(unsigned int, unsigned_int);
77 REGISTER_TYPE_CONVERTER(signed int, signed_int);
78 REGISTER_TYPE_CONVERTER(unsigned long, unsigned_long);
79 REGISTER_TYPE_CONVERTER(signed long, signed_long);
80 REGISTER_TYPE_CONVERTER(gate_uint64_t, unsigned_longlong);
81 REGISTER_TYPE_CONVERTER(gate_int64_t, signed_longlong);
82 REGISTER_TYPE_CONVERTER(float, float);
83 REGISTER_TYPE_CONVERTER(double, double);
84 REGISTER_TYPE_CONVERTER(long double, longdouble);
85 REGISTER_TYPE_CONVERTER(void*, pointer);
86
87 #define CONVERT_TYPE_TO_GENERIC(arg_type_name, input_value, output_ptr, output_count, output_max) do { \
88 arg_type_name ## _converter_t converter = GATE_INIT_EMPTY; \
89 if(sizeof(input_value) > (sizeof(fparam_t) * output_max)) \
90 { \
91 *output_count = 0; \
92 } \
93 else \
94 { \
95 converter.native_value = input_value; \
96 *output_count = sizeof(converter.generic_value) / sizeof(fparam_t); \
97 gate_mem_copy(output_ptr, &converter.generic_value[0], sizeof(converter.generic_value)); \
98 } \
99 } while(0)
100
101 #if defined(GATE_SYS_WIN)
102 #else
103 # define GATE_FUNCTION_ARGS_MAX_ALIGNMENT
104 #endif
105
106 15 static unsigned gate_function_load_argument(gate_function_argument_t* arg, fparam_t* target, unsigned target_count)
107 {
108 15 unsigned target_used = 0;
109
110
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))
111 {
112 return 0;
113 }
114
115
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)
116 {
117 2 case GATE_FUNCTION_ARG_UCHAR:
118 {
119
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);
120 2 break;
121 }
122 1 case GATE_FUNCTION_ARG_SCHAR:
123 {
124
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);
125 1 break;
126 }
127 2 case GATE_FUNCTION_ARG_USHORT:
128 {
129
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);
130 2 break;
131 }
132 1 case GATE_FUNCTION_ARG_SSHORT:
133 {
134
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);
135 1 break;
136 }
137 1 case GATE_FUNCTION_ARG_UINT:
138 {
139
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);
140 1 break;
141 }
142 1 case GATE_FUNCTION_ARG_SINT:
143 {
144
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);
145 1 break;
146 }
147 2 case GATE_FUNCTION_ARG_ULONG:
148 {
149
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);
150 2 break;
151 }
152 1 case GATE_FUNCTION_ARG_SLONG:
153 {
154
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);
155 1 break;
156 }
157 2 case GATE_FUNCTION_ARG_ULONGLONG:
158 {
159
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);
160 2 break;
161 }
162 1 case GATE_FUNCTION_ARG_SLONGLONG:
163 {
164
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);
165 1 break;
166 }
167 case GATE_FUNCTION_ARG_FLOAT:
168 {
169 CONVERT_TYPE_TO_GENERIC(float, arg->arg_value.flt, target, &target_used, target_count);
170 break;
171 }
172 case GATE_FUNCTION_ARG_DOUBLE:
173 {
174 CONVERT_TYPE_TO_GENERIC(double, arg->arg_value.dbl, target, &target_used, target_count);
175 break;
176 }
177 case GATE_FUNCTION_ARG_LONGDOUBLE:
178 {
179 CONVERT_TYPE_TO_GENERIC(longdouble, arg->arg_value.ldbl, target, &target_used, target_count);
180 break;
181 }
182 1 case GATE_FUNCTION_ARG_POINTER:
183 {
184
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);
185 1 break;
186 }
187 case GATE_FUNCTION_ARG_BLOB:
188 {
189 CONVERT_TYPE_TO_GENERIC(unsigned_char, arg->arg_value.u_chr, target, &target_used, target_count);
190 break;
191 }
192 }
193 15 return target_used;
194 }
195
196 3 gate_result_t gate_function_invoke_generic(gate_funcptr_t func_ptr, gate_enumint_t flags,
197 gate_function_argument_t* args, gate_size_t arg_count,
198 gate_function_argument_t* retval)
199 {
200 3 fparam_t v[64] = GATE_INIT_EMPTY;
201 3 fparam_t* ptr_v = &v[0];
202 3 unsigned count = sizeof(v) / sizeof(v[0]);
203 3 gate_uint64_t r = 0;
204 3 gate_function_generic_t func = (gate_function_generic_t)func_ptr;
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 unsigned used, n;
211 fparam_t tmp[16];
212 15 gate_mem_clear(tmp, sizeof(tmp));
213 15 used = gate_function_load_argument(args, tmp, sizeof(tmp) / sizeof(tmp[0]));
214
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (used > count)
215 {
216 return GATE_RESULT_OUTOFMEMORY;
217 }
218 #if defined(GATE_FUNCTION_ARGS_MAX_ALIGNMENT)
219 /* type was greater than pointer, add padding words to extend alignment */
220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (used > 1)
221 {
222 unsigned mod;
223 mod = count % used;
224 if (mod > 0)
225 {
226 unsigned padd = used - mod;
227 if (padd > count)
228 {
229 return GATE_RESULT_OUTOFMEMORY;
230 }
231 for (n = 0; n != padd; ++n)
232 {
233 ptr_v[n] = ((fparam_t)0);
234 }
235 ptr_v += padd;
236 count -= padd;
237 }
238 }
239 #else
240 /* we are pointer-aligned -> nothing to do */
241 #endif
242
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 for (n = 0; n != used; ++n)
243 {
244 15 ptr_v[n] = tmp[n];
245 }
246 15 ptr_v += used;
247 15 count -= used;
248 15 ++args;
249 }
250
251 3 r = func(
252 v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9],
253 v[10], v[11], v[12], v[13], v[14], v[15], v[16], v[17], v[18], v[19],
254 v[20], v[21], v[22], v[23], v[24], v[25], v[26], v[27], v[28], v[29],
255 v[30], v[31], v[32], v[33], v[34], v[35], v[36], v[37], v[38], v[39],
256 v[40], v[41], v[42], v[43], v[44], v[45], v[46], v[47], v[48], v[49],
257 v[50], v[51], v[52], v[53], v[54], v[55], v[56], v[57], v[58], v[59],
258 v[60], v[61], v[62], v[63]
259 );
260
261
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (retval)
262 {
263 3 retval->arg_value.u_long_long = r;
264 3 retval->arg_type = GATE_FUNCTION_ARG_ULONGLONG;
265 }
266
267 3 return GATE_RESULT_OK;
268 }
269
270 #endif
271
272
273 #if defined(GATE_FUNCTIONS_X86_IMPL)
274
275 typedef union x86_arguments
276 {
277 void* function_ptr;
278 unsigned char buffer[1024];
279 } x86_arguments_t;
280
281 typedef gate_uint64_t(*x86_c_func_t)(x86_arguments_t args);
282
283 gate_result_t gate_function_invoke_generic(void* func_ptr, gate_enumint_t flags,
284 gate_function_argument_t* args, gate_size_t arg_count, gate_function_argument_t* retval)
285 {
286 gate_result_t ret = GATE_RESULT_OK;
287 x86_c_func_t func = (x86_c_func_t)func_ptr;
288 gate_uint64_t x86_ret = NULL;
289 x86_arguments_t x86_args = GATE_INIT_EMPTY;
290 gate_size_t n;
291
292 for (n = 0; n != sizeof(x86_args.buffer); ++n)
293 {
294 x86_args.buffer[n] = (unsigned char)(n % 256);
295 }
296
297 x86_ret = func(x86_args);
298 if (retval)
299 {
300 retval->arg_value.u_long_long = x86_ret;
301 retval->arg_type = GATE_FUNCTION_ARG_ULONGLONG;
302 }
303 return ret;
304 }
305
306
307 #endif /* GATE_FUNCTIONS_X86_IMPL */
308
309 #if defined(GATE_FUNCTIONS_X86X64_IMPL)
310
311 typedef void* (*x64_c_func_t)(
312 void* a1, void* a2, void* a3, void* a4, void* a5, void* a6, void* a7, void* a8,
313 void* b1, void* b2, void* b3, void* b4, void* b5, void* b6, void* b7, void* b8,
314 void* c1, void* c2, void* c3, void* c4, void* c5, void* c6, void* c7, void* c8,
315 void* d1, void* d2, void* d3, void* d4, void* d5, void* d6, void* d7, void* d8,
316 void* e1, void* e2, void* e3, void* e4, void* e5, void* e6, void* e7, void* e8,
317 void* f1, void* f2, void* f3, void* f4, void* f5, void* f6, void* f7, void* f8
318 );
319
320 gate_result_t gate_function_invoke_generic(void* func_ptr, gate_enumint_t flags,
321 gate_function_argument_t* args, gate_size_t arg_count, gate_function_argument_t* retval)
322 {
323 gate_result_t ret = GATE_RESULT_OK;
324 x64_c_func_t func = (x64_c_func_t)func_ptr;
325 void* x64_ret = NULL;
326 gate_size_t n, i;
327 void* a[8];
328 void* b[8];
329 void* c[8];
330 void* d[8];
331 void* e[8];
332 void* f[8];
333
334 i = 0;
335 for (n = 0; n != 8; ++n) a[n] = (unsigned char)(i++ % 256);
336 for (n = 0; n != 8; ++n) b[n] = (unsigned char)(i++ % 256);
337 for (n = 0; n != 8; ++n) c[n] = (unsigned char)(i++ % 256);
338 for (n = 0; n != 8; ++n) d[n] = (unsigned char)(i++ % 256);
339 for (n = 0; n != 8; ++n) e[n] = (unsigned char)(i++ % 256);
340 for (n = 0; n != 8; ++n) f[n] = (unsigned char)(i++ % 256);
341
342 x64_ret = func(
343 a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
344 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
345 c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7],
346 d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
347 e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7],
348 f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]
349 );
350 if (retval)
351 {
352 retval->arg_value.u_long_long = x64_ret;
353 retval->arg_type = GATE_FUNCTION_ARG_ULONGLONG;
354 }
355
356 return ret;
357 }
358
359 #endif /* GATE_FUNCTIONS_X86X64_IMPL */
360
361
362
363 #if defined(GATE_FUNCTION_GUARD_WINSEH)
364
365 #include "gate/platforms.h"
366
367 static int gate_win32_seh_filter(unsigned int seh_code,
368 struct _EXCEPTION_POINTERS* xcpt_ptrs,
369 gate_function_fault_handler_t handler, void* param)
370 {
371 unsigned fault_code;
372 gate_result_t result;
373
374 GATE_UNUSED_ARG(xcpt_ptrs);
375
376 switch (seh_code)
377 {
378 case EXCEPTION_FLT_DENORMAL_OPERAND:
379 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
380 case EXCEPTION_FLT_INEXACT_RESULT:
381 case EXCEPTION_FLT_INVALID_OPERATION:
382 case EXCEPTION_FLT_OVERFLOW:
383 case EXCEPTION_FLT_STACK_CHECK:
384 case EXCEPTION_FLT_UNDERFLOW:
385 fault_code = GATE_FUNCTION_FAULT_FLOAT;
386 break;
387 case EXCEPTION_ACCESS_VIOLATION:
388 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
389 case EXCEPTION_GUARD_PAGE:
390 case EXCEPTION_IN_PAGE_ERROR:
391 fault_code = GATE_FUNCTION_FAULT_ADDRESS;
392 break;
393 case EXCEPTION_ILLEGAL_INSTRUCTION:
394 fault_code = GATE_FUNCTION_FAULT_INSTRUCTION;
395 break;
396 case EXCEPTION_SINGLE_STEP:
397 case EXCEPTION_BREAKPOINT:
398 fault_code = GATE_FUNCTION_FAULT_BREAKPOINT;
399 break;
400 case EXCEPTION_DATATYPE_MISALIGNMENT:
401 fault_code = GATE_FUNCTION_FAULT_ALIGNMENT;
402 break;
403 case EXCEPTION_INT_DIVIDE_BY_ZERO:
404 fault_code = GATE_FUNCTION_FAULT_ARITHMETIC;
405 break;
406 case EXCEPTION_INT_OVERFLOW:
407 fault_code = GATE_FUNCTION_FAULT_OVERFLOW;
408 break;
409 case EXCEPTION_INVALID_HANDLE:
410 fault_code = GATE_FUNCTION_FAULT_SYSTEM;
411 break;
412 case EXCEPTION_PRIV_INSTRUCTION:
413 fault_code = GATE_FUNCTION_FAULT_PRIVILEGE;
414 break;
415 case EXCEPTION_STACK_OVERFLOW:
416 fault_code = GATE_FUNCTION_FAULT_STACK;
417 break;
418 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
419 case EXCEPTION_INVALID_DISPOSITION:
420 default:
421 fault_code = GATE_FUNCTION_FAULT_UNKNOWN;
422 break;
423 }
424
425 if (handler)
426 {
427 result = handler(fault_code, param);
428 if (GATE_FAILED(result))
429 {
430 return EXCEPTION_CONTINUE_SEARCH;
431 }
432 }
433 return EXCEPTION_EXECUTE_HANDLER;
434 }
435
436
437 gate_result_t gate_function_invoke_guarded(gate_entrypoint_t entry_point, void* entry_param,
438 gate_function_fault_handler_t fault_handler, void* fault_param)
439 {
440 gate_result_t result = GATE_RESULT_OK;
441 __try
442 {
443 if (entry_point)
444 {
445 result = entry_point(entry_param);
446 }
447 }
448 __except (gate_win32_seh_filter(GetExceptionCode(), GetExceptionInformation(), fault_handler, fault_param))
449 {
450 result = GATE_RESULT_BADINSTRUCTION;
451 }
452 return result;
453 }
454
455 #endif /* GATE_FUNCTION_GUARD_WINSEH */
456
457
458
459 #if defined(GATE_FUNCTION_GUARD_SIGNALS)
460
461 #include "gate/atomics.h"
462 #include "gate/platforms.h"
463 #include "gate/callstacks.h"
464 #include "gate/threading.h"
465 #include <setjmp.h>
466 #include <signal.h>
467
468
469 static gate_thread_storage_t global_function_guard_registry;
470 static gate_atomic_flag_t global_function_guard_registry_initialized = GATE_ATOMIC_FLAG_INIT;
471
472 typedef struct gate_function_anchor_class
473 {
474 gate_callstack_jmpbuf_t context;
475 gate_function_fault_handler_t fault_handler;
476 void* fault_param;
477 } gate_function_anchor_t;
478
479
480 static void gate_function_guard_signal_handler(int signum);
481
482 3 static gate_result_t gate_function_guard_init()
483 {
484 3 gate_result_t ret = GATE_RESULT_OK;
485
486
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
3 if (false == gate_atomic_flag_set(&global_function_guard_registry_initialized))
487 {
488 1 ret = gate_thread_storage_alloc(&global_function_guard_registry);
489
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(ret))
490 {
491 gate_atomic_flag_clear(&global_function_guard_registry_initialized);
492 return ret;
493 }
494 }
495
496 3 gate_platform_set_signal_handler(SIGABRT, &gate_function_guard_signal_handler, NULL);
497 #ifdef SIGBUS
498 3 gate_platform_set_signal_handler(SIGBUS, &gate_function_guard_signal_handler, NULL);
499 #endif
500 3 gate_platform_set_signal_handler(SIGFPE, &gate_function_guard_signal_handler, NULL);
501 3 gate_platform_set_signal_handler(SIGILL, &gate_function_guard_signal_handler, NULL);
502 3 gate_platform_set_signal_handler(SIGSEGV, &gate_function_guard_signal_handler, NULL);
503 #ifdef SIGSYS
504 3 gate_platform_set_signal_handler(SIGSYS, &gate_function_guard_signal_handler, NULL);
505 #endif
506 #ifdef SIGTRAP
507 3 gate_platform_set_signal_handler(SIGTRAP, &gate_function_guard_signal_handler, NULL);
508 #endif
509 3 return ret;
510 }
511
512 static unsigned translate_signal(int sig)
513 {
514 switch (sig)
515 {
516 case SIGSEGV: return GATE_FUNCTION_FAULT_ADDRESS;
517 #ifdef SIGBUS
518 case SIGBUS: return GATE_FUNCTION_FAULT_ADDRESS;
519 #endif
520 case SIGABRT: return GATE_FUNCTION_FAULT_ADDRESS;
521
522 case SIGILL: return GATE_FUNCTION_FAULT_INSTRUCTION;
523 case SIGFPE: return GATE_FUNCTION_FAULT_ARITHMETIC;
524
525 #ifdef SIGSYS
526 case SIGSYS: return GATE_FUNCTION_FAULT_SYSTEM;
527 #endif
528 #ifdef SIGTRAP
529 case SIGTRAP: return GATE_FUNCTION_FAULT_BREAKPOINT;
530 #endif
531 }
532 return GATE_FUNCTION_FAULT_UNKNOWN;
533 }
534
535 static void gate_function_guard_signal_handler(int signum)
536 {
537 gate_function_anchor_t* ptr_anchor = NULL;
538 gate_result_t result = gate_thread_storage_get(&global_function_guard_registry, (void**)&ptr_anchor);
539 if (GATE_SUCCEEDED(result) && (ptr_anchor != NULL))
540 {
541 unsigned const fault_code = translate_signal(signum);
542 result = ptr_anchor->fault_handler(fault_code, ptr_anchor->fault_param);
543 if (GATE_SUCCEEDED(result))
544 {
545 gate_callstack_jump(&ptr_anchor->context);
546 }
547 }
548 }
549
550 static gate_result_t gate_function_guard_error_branch(void* param)
551 {
552 (void)param;
553 return GATE_RESULT_BADINSTRUCTION;
554 }
555
556 3 gate_result_t gate_function_invoke_guarded(gate_entrypoint_t entry_point, void* entry_param,
557 gate_function_fault_handler_t fault_handler, void* fault_param)
558 {
559 3 volatile gate_result_t ret = GATE_RESULT_FAILED;
560 gate_function_anchor_t new_anchor;
561 3 gate_function_anchor_t* ptr_old_anchor = NULL;
562
563 3 ret = gate_function_guard_init();
564
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(ret))
565 {
566 return ret;
567 }
568
569 3 gate_thread_storage_get(&global_function_guard_registry, (void**)&ptr_old_anchor);
570 3 new_anchor.fault_handler = fault_handler;
571 3 new_anchor.fault_param = fault_param;
572
573 3 ret = gate_thread_storage_set(&global_function_guard_registry, &new_anchor);
574
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(ret))
575 {
576 return ret;
577 }
578
579 3 ret = gate_callstack_fork(&new_anchor.context, entry_point, entry_param, &gate_function_guard_error_branch, NULL);
580
581 3 gate_thread_storage_set(&global_function_guard_registry, ptr_old_anchor);
582 3 return ret;
583 }
584
585 #endif /* GATE_FUNCTION_GUARD_SIGNALS */
586
587 #if defined(GATE_FUNCTION_GUARD_NOGUARD)
588
589 gate_result_t gate_function_invoke_guarded(gate_entrypoint_t entry_point, void* entry_param,
590 gate_function_fault_handler_t fault_handler, void* fault_param)
591 {
592 gate_result_t ret;
593
594 ret = entry_point(entry_param);
595 return ret;
596 }
597
598 #endif /* GATE_FUNCTION_GUARD_NOGUARD */
599
600