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