| 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 |