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 | |||
29 | #include "gate/callstacks.h" | ||
30 | #include "gate/strings.h" | ||
31 | #include "gate/results.h" | ||
32 | #include "gate/platforms.h" | ||
33 | |||
34 | |||
35 | #if defined(GATE_SYS_WINCE) | ||
36 | # define GATE_CALLSTACKS_WINCE_TRACE_IMPL 1 | ||
37 | # define GATE_CALLSTACKS_DEFAULT_SETJMP 1 | ||
38 | # define GATE_CALLSTACKS_WIN32_CALLSTACK_IMPL | ||
39 | #elif defined(GATE_SYS_WASM) | ||
40 | # define GATE_CALLSTACKS_NO_IMPL 1 | ||
41 | # define GATE_CALLSTACKS_NO_FORK_IMPL 1 | ||
42 | #elif defined(GATE_SYS_DOS) | ||
43 | # define GATE_CALLSTACKS_DEFAULT_SETJMP 1 | ||
44 | # define GATE_CALLSTACKS_DOS_IMPL 1 | ||
45 | #elif defined(GATE_SYS_WIN) && !defined(GATE_SYS_WIN16) | ||
46 | # define GATE_CALLSTACKS_WIN32_TRACE_DBG_IMPL 1 | ||
47 | # define GATE_CALLSTACKS_DEFAULT_SETJMP 1 | ||
48 | # define GATE_CALLSTACKS_WIN32_CALLSTACK_IMPL | ||
49 | #elif defined(GATE_SYS_BEOS) | ||
50 | # define GATE_CALLSTACKS_NO_IMPL 1 | ||
51 | # define GATE_CALLSTACKS_DEFAULT_SETJMP 1 | ||
52 | #elif defined(GATE_SYS_ANDROID) | ||
53 | # define GATE_CALLSTACKS_NO_IMPL 1 | ||
54 | # define GATE_CALLSTACKS_DEFAULT_SETJMP 1 | ||
55 | #elif defined(GATE_SYS_POSIX) | ||
56 | # define GATE_CALLSTACKS_POSIX_IMPL 1 | ||
57 | #elif defined(GATE_SYS_EFI) | ||
58 | # define GATE_CALLSTACKS_EFI_IMPL 1 | ||
59 | # define GATE_CALLSTACKS_DEFAULT_SETJMP 1 | ||
60 | #else | ||
61 | # define GATE_CALLSTACKS_NO_IMPL 1 | ||
62 | # define GATE_CALLSTACKS_DEFAULT_SETJMP 1 | ||
63 | #endif | ||
64 | |||
65 | |||
66 | #if defined(GATE_CALLSTACKS_NO_FORK_IMPL) | ||
67 | gate_result_t gate_callstack_fork(gate_callstack_jmpbuf_t* jmpbuffer, | ||
68 | gate_entrypoint_t entry, void* param, | ||
69 | gate_entrypoint_t branch, void* branch_param) | ||
70 | { | ||
71 | return GATE_RESULT_NOTIMPLEMENTED; | ||
72 | } | ||
73 | |||
74 | void gate_callstack_jump(gate_callstack_jmpbuf_t* jmpbuffer) | ||
75 | { | ||
76 | } | ||
77 | |||
78 | #endif /* GATE_CALLSTACKS_NO_FORK_IMPL */ | ||
79 | |||
80 | #if defined(GATE_CALLSTACKS_DEFAULT_SETJMP) | ||
81 | |||
82 | #if defined(GATE_SYS_EFI) && defined(GATE_COMPILER_MSVC) && (_MSC_VER < 1930) | ||
83 | typedef void* jmp_buf[48]; | ||
84 | #define setjmp _setjmp | ||
85 | extern int setjmp(jmp_buf buf); | ||
86 | extern void longjmp(jmp_buf buf, int n); | ||
87 | #else | ||
88 | #include <setjmp.h> | ||
89 | #endif | ||
90 | |||
91 | typedef struct gate_native_jmp_buf_class | ||
92 | { | ||
93 | jmp_buf buf; | ||
94 | } gate_native_jmp_buf_t; | ||
95 | |||
96 | gate_result_t gate_callstack_fork(gate_callstack_jmpbuf_t* jmpbuffer, | ||
97 | gate_entrypoint_t entry, void* param, | ||
98 | gate_entrypoint_t branch, void* branch_param) | ||
99 | { | ||
100 | gate_result_t ret = GATE_RESULT_OK; | ||
101 | gate_native_jmp_buf_t* ptr_buf = (gate_native_jmp_buf_t*)jmpbuffer; | ||
102 | if (0 == setjmp(ptr_buf->buf)) | ||
103 | { | ||
104 | if (entry) | ||
105 | { | ||
106 | ret = entry(param); | ||
107 | } | ||
108 | } | ||
109 | else | ||
110 | { | ||
111 | if (branch) | ||
112 | { | ||
113 | ret = branch(branch_param); | ||
114 | } | ||
115 | } | ||
116 | gate_mem_clear(jmpbuffer, sizeof(gate_callstack_jmpbuf_t)); | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | void gate_callstack_jump(gate_callstack_jmpbuf_t* jmpbuffer) | ||
121 | { | ||
122 | gate_native_jmp_buf_t* ptr_buf = (gate_native_jmp_buf_t*)jmpbuffer; | ||
123 | longjmp(ptr_buf->buf, 1); | ||
124 | } | ||
125 | |||
126 | #endif /* GATE_CALLSTACKS_DEFAULT_SETJMP */ | ||
127 | |||
128 | |||
129 | |||
130 | |||
131 | #if defined(GATE_CALLSTACKS_WINCE_TRACE_IMPL) | ||
132 | |||
133 | #include "gate/libraries.h" | ||
134 | |||
135 | #include <windows.h> | ||
136 | #if defined(GATE_COMPILER_MSVC) | ||
137 | #include <Kfuncs.h> | ||
138 | #endif | ||
139 | |||
140 | typedef struct _CallSnapshot | ||
141 | { | ||
142 | DWORD dwReturnAddr; | ||
143 | } CallSnapshot; | ||
144 | |||
145 | typedef ULONG(*GetThreadCallStack_t)( | ||
146 | HANDLE hThrd, | ||
147 | ULONG dwMaxFrames, | ||
148 | LPVOID lpFrames[], | ||
149 | DWORD dwFlags, | ||
150 | DWORD dwSkip | ||
151 | ); | ||
152 | |||
153 | |||
154 | static gate_library_t gate_callstack_lib = NULL; | ||
155 | static GetThreadCallStack_t GetThreadCallStackFunction = NULL; | ||
156 | |||
157 | static gate_bool_t gate_callstack_init() | ||
158 | { | ||
159 | static gate_string_t const lib_binary = { "coredll.dll", 11, NULL }; | ||
160 | gate_result_t ret; | ||
161 | |||
162 | if (gate_callstack_lib == NULL) | ||
163 | { | ||
164 | ret = gate_library_open(&lib_binary, &gate_callstack_lib, 0); | ||
165 | if (GATE_FAILED(ret)) | ||
166 | { | ||
167 | return false; | ||
168 | } | ||
169 | } | ||
170 | if (GetThreadCallStackFunction == NULL) | ||
171 | { | ||
172 | ret = gate_library_get_function_name(gate_callstack_lib, "GetThreadCallStack", &GetThreadCallStackFunction); | ||
173 | if (GATE_FAILED(ret)) | ||
174 | { | ||
175 | return false; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | return true; | ||
180 | } | ||
181 | |||
182 | gate_result_t gate_callstack_trace(gate_callstack_address_t* addresses, gate_size_t addresses_count, gate_size_t* addresses_used) | ||
183 | { | ||
184 | HANDLE hThread = GetCurrentThread(); | ||
185 | CallSnapshot stack_addresses[1024]; | ||
186 | DWORD dwCount, dwIndex; | ||
187 | |||
188 | if (!gate_callstack_init()) | ||
189 | { | ||
190 | return GATE_RESULT_NOTSUPPORTED; | ||
191 | } | ||
192 | |||
193 | dwCount = GetThreadCallStackFunction(hThread, sizeof(stack_addresses) / sizeof(stack_addresses[0]), | ||
194 | (void**)&stack_addresses[0], 0, 0); | ||
195 | |||
196 | if (dwCount > addresses_count) | ||
197 | { | ||
198 | dwCount = addresses_count; | ||
199 | } | ||
200 | for (dwIndex = 0; dwIndex != dwCount; ++dwIndex) | ||
201 | { | ||
202 | addresses[dwIndex] = (gate_callstack_address_t)stack_addresses[dwIndex].dwReturnAddr; | ||
203 | } | ||
204 | if (addresses_used != NULL) | ||
205 | { | ||
206 | *addresses_used = dwCount; | ||
207 | } | ||
208 | return GATE_RESULT_OK; | ||
209 | } | ||
210 | gate_result_t gate_callstack_print(gate_callstack_address_t address, char* buffer, gate_size_t buffer_length, gate_size_t* buffer_used) | ||
211 | { | ||
212 | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | ||
213 | |||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | #endif /* GATE_CALLSTACKS_WINCE_IMPL */ | ||
218 | |||
219 | |||
220 | |||
221 | |||
222 | |||
223 | #if defined(GATE_CALLSTACKS_WIN32_TRACE_DBG_IMPL) | ||
224 | |||
225 | #include "gate/libraries.h" | ||
226 | |||
227 | #define WIN32_LEAN_AND_MEAN | ||
228 | #include <tchar.h> | ||
229 | #include <windows.h> | ||
230 | |||
231 | #include "gate/platforms.h" | ||
232 | |||
233 | static gate_library_t gate_win32_dbghlp_module = NULL; | ||
234 | |||
235 | #define MAX_SYM_NAME 2000 | ||
236 | |||
237 | typedef enum | ||
238 | { | ||
239 | SymNone = 0, | ||
240 | SymCoff, | ||
241 | SymCv, | ||
242 | SymPdb, | ||
243 | SymExport, | ||
244 | SymDeferred, | ||
245 | SymSym, // .sym file | ||
246 | SymDia, | ||
247 | SymVirtual, | ||
248 | NumSymTypes | ||
249 | } SYM_TYPE; | ||
250 | |||
251 | typedef struct _IMAGEHLP_MODULE64 | ||
252 | { | ||
253 | DWORD SizeOfStruct; /* set to sizeof(IMAGEHLP_MODULE64) */ | ||
254 | DWORD64 BaseOfImage; /* base load address of module */ | ||
255 | DWORD ImageSize; /* virtual size of the loaded module */ | ||
256 | DWORD TimeDateStamp; /* date/time stamp from pe header */ | ||
257 | DWORD CheckSum; /* checksum from the pe header */ | ||
258 | DWORD NumSyms; /* number of symbols in the symbol table */ | ||
259 | SYM_TYPE SymType; /* type of symbols loaded */ | ||
260 | CHAR ModuleName[32]; /* module name */ | ||
261 | CHAR ImageName[256]; /* image name */ | ||
262 | /* new elements: 07-Jun-2002 */ | ||
263 | CHAR LoadedImageName[256]; /* symbol file name */ | ||
264 | CHAR LoadedPdbName[256]; /* pdb file name */ | ||
265 | DWORD CVSig; /* Signature of the CV record in the debug directories */ | ||
266 | CHAR CVData[MAX_PATH * 3]; /* Contents of the CV record */ | ||
267 | DWORD PdbSig; /* Signature of PDB */ | ||
268 | GUID PdbSig70; /* Signature of PDB (VC 7 and up) */ | ||
269 | DWORD PdbAge; /* DBI age of pdb */ | ||
270 | BOOL PdbUnmatched; /* loaded an unmatched pdb */ | ||
271 | BOOL DbgUnmatched; /* loaded an unmatched dbg */ | ||
272 | BOOL LineNumbers; /* we have line number information */ | ||
273 | BOOL GlobalSymbols; /* we have internal symbol information */ | ||
274 | BOOL TypeInfo; /* we have type information */ | ||
275 | } IMAGEHLP_MODULE64, * PIMAGEHLP_MODULE64; | ||
276 | |||
277 | typedef PVOID(WINAPI* PtrSymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase); | ||
278 | static PtrSymFunctionTableAccess64 SymFunctionTableAccess64 = NULL; | ||
279 | |||
280 | typedef DWORD64(WINAPI* PtrSymGetModuleBase64)(HANDLE hProcess, DWORD64 qwAddr); | ||
281 | static PtrSymGetModuleBase64 SymGetModuleBase64 = NULL; | ||
282 | |||
283 | typedef enum | ||
284 | { | ||
285 | AddrMode1616, | ||
286 | AddrMode1632, | ||
287 | AddrModeReal, | ||
288 | AddrModeFlat | ||
289 | } ADDRESS_MODE; | ||
290 | |||
291 | typedef struct _tagADDRESS64 | ||
292 | { | ||
293 | DWORD64 Offset; | ||
294 | WORD Segment; | ||
295 | ADDRESS_MODE Mode; | ||
296 | } ADDRESS64, * LPADDRESS64; | ||
297 | |||
298 | |||
299 | typedef BOOL(__stdcall* PREAD_PROCESS_MEMORY_ROUTINE64)( | ||
300 | HANDLE hProcess, | ||
301 | DWORD64 qwBaseAddress, | ||
302 | PVOID lpBuffer, | ||
303 | DWORD nSize, | ||
304 | LPDWORD lpNumberOfBytesRead | ||
305 | ); | ||
306 | |||
307 | typedef PVOID(__stdcall* PFUNCTION_TABLE_ACCESS_ROUTINE64)( | ||
308 | HANDLE hProcess, | ||
309 | DWORD64 AddrBase | ||
310 | ); | ||
311 | |||
312 | typedef DWORD64(__stdcall* PGET_MODULE_BASE_ROUTINE64)( | ||
313 | HANDLE hProcess, | ||
314 | DWORD64 Address | ||
315 | ); | ||
316 | |||
317 | typedef DWORD64(__stdcall* PTRANSLATE_ADDRESS_ROUTINE64)( | ||
318 | HANDLE hProcess, | ||
319 | HANDLE hThread, | ||
320 | LPADDRESS64 lpaddr | ||
321 | ); | ||
322 | |||
323 | typedef struct _KDHELP64 | ||
324 | { | ||
325 | DWORD64 Thread; | ||
326 | DWORD ThCallbackStack; | ||
327 | DWORD ThCallbackBStore; | ||
328 | DWORD NextCallback; | ||
329 | DWORD FramePointer; | ||
330 | DWORD64 KiCallUserMode; | ||
331 | DWORD64 KeUserCallbackDispatcher; | ||
332 | DWORD64 SystemRangeStart; | ||
333 | DWORD64 Reserved[8]; | ||
334 | } KDHELP64, * PKDHELP64; | ||
335 | |||
336 | typedef struct _tagSTACKFRAME64 | ||
337 | { | ||
338 | ADDRESS64 AddrPC; | ||
339 | ADDRESS64 AddrReturn; | ||
340 | ADDRESS64 AddrFrame; | ||
341 | ADDRESS64 AddrStack; | ||
342 | ADDRESS64 AddrBStore; | ||
343 | PVOID FuncTableEntry; | ||
344 | DWORD64 Params[4]; | ||
345 | BOOL Far; | ||
346 | BOOL Virtual; | ||
347 | DWORD64 Reserved[3]; | ||
348 | KDHELP64 KdHelp; | ||
349 | } STACKFRAME64, * LPSTACKFRAME64; | ||
350 | |||
351 | typedef BOOL(WINAPI* PtrSymInitialize)(HANDLE, PCSTR, BOOL); | ||
352 | static PtrSymInitialize SymInitialize = NULL; | ||
353 | |||
354 | typedef BOOL(WINAPI* PtrSymCleanup)(HANDLE); | ||
355 | static PtrSymCleanup SymCleanup = NULL; | ||
356 | |||
357 | typedef struct _IMAGEHLP_SYMBOL64 | ||
358 | { | ||
359 | DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64) | ||
360 | DWORD64 Address; // virtual address including dll base address | ||
361 | DWORD Size; // estimated size of symbol, can be zero | ||
362 | DWORD Flags; // info about the symbols, see the SYMF defines | ||
363 | DWORD MaxNameLength; // maximum size of symbol name in 'Name' | ||
364 | CHAR Name[1]; // symbol name (null terminated string) | ||
365 | } IMAGEHLP_SYMBOL64, * PIMAGEHLP_SYMBOL64; | ||
366 | |||
367 | typedef BOOL(WINAPI* PtrStackWalk64)( | ||
368 | DWORD MachineType, | ||
369 | HANDLE hProcess, | ||
370 | HANDLE hThread, | ||
371 | LPSTACKFRAME64 StackFrame, | ||
372 | PVOID ContextRecord, | ||
373 | PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, | ||
374 | PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, | ||
375 | PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, | ||
376 | PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress | ||
377 | ); | ||
378 | static PtrStackWalk64 StackWalk64 = NULL; | ||
379 | |||
380 | |||
381 | typedef BOOL(WINAPI* PtrSymGetModuleInfo64)(HANDLE hProcess, DWORD64 qwAddr, PIMAGEHLP_MODULE64 ModuleInfo); | ||
382 | static PtrSymGetModuleInfo64 SymGetModuleInfo64 = NULL; | ||
383 | |||
384 | typedef BOOL(WINAPI* PtrSymGetSymFromAddr64)(HANDLE hProcess, DWORD64 qwAddr, PDWORD64 pdwDisplacement, PIMAGEHLP_SYMBOL64 Symbol); | ||
385 | static PtrSymGetSymFromAddr64 SymGetSymFromAddr64 = NULL; | ||
386 | |||
387 | static gate_bool_t gate_callstack_load_api(void* ptr_to_func_ptr, char const* func_name) | ||
388 | { | ||
389 | gate_result_t ret; | ||
390 | |||
391 | if ((*(void**)ptr_to_func_ptr) == NULL) | ||
392 | { | ||
393 | ret = gate_library_get_function_name(gate_win32_dbghlp_module, func_name, ptr_to_func_ptr); | ||
394 | if (GATE_FAILED(ret)) | ||
395 | { | ||
396 | return false; | ||
397 | } | ||
398 | } | ||
399 | return true; | ||
400 | } | ||
401 | |||
402 | static gate_bool_t gate_callstack_init() | ||
403 | { | ||
404 | static gate_string_t const str_dbghelp = { "Dbghelp.dll", 11, NULL }; | ||
405 | gate_result_t ret; | ||
406 | |||
407 | if (gate_win32_dbghlp_module == NULL) | ||
408 | { | ||
409 | ret = gate_library_open(&str_dbghelp, &gate_win32_dbghlp_module, 0); | ||
410 | if (GATE_FAILED(ret)) | ||
411 | { | ||
412 | return false; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | ret = true; | ||
417 | ret &= gate_callstack_load_api(&SymInitialize, "SymInitialize"); | ||
418 | ret &= gate_callstack_load_api(&SymCleanup, "SymCleanup"); | ||
419 | ret &= gate_callstack_load_api(&StackWalk64, "StackWalk64"); | ||
420 | ret &= gate_callstack_load_api(&SymGetModuleInfo64, "SymGetModuleInfo64"); | ||
421 | ret &= gate_callstack_load_api(&SymGetSymFromAddr64, "SymGetSymFromAddr64"); | ||
422 | ret &= gate_callstack_load_api(&SymFunctionTableAccess64, "SymFunctionTableAccess64"); | ||
423 | ret &= gate_callstack_load_api(&SymGetModuleBase64, "SymGetModuleBase64"); | ||
424 | ret &= gate_callstack_load_api(&SymInitialize, "SymInitialize"); | ||
425 | ret &= gate_callstack_load_api(&SymInitialize, "SymInitialize"); | ||
426 | ret &= gate_callstack_load_api(&SymInitialize, "SymInitialize"); | ||
427 | |||
428 | return ret; | ||
429 | } | ||
430 | |||
431 | #ifndef IMAGE_FILE_MACHINE_I386 | ||
432 | #define IMAGE_FILE_MACHINE_I386 0x014c | ||
433 | #endif | ||
434 | |||
435 | #ifndef IMAGE_FILE_MACHINE_AMD64 | ||
436 | #define IMAGE_FILE_MACHINE_AMD64 0x8664 | ||
437 | #endif | ||
438 | |||
439 | #if defined(GATE_COMPILER_MSVC) || defined(GATE_COMPILER_CLANG) | ||
440 | # define GATE_WINAPI_CPU_CONTEXT CONTEXT | ||
441 | # if (GATE_ARCH == GATE_ARCH_X86X64) | ||
442 | # define MACHINE_FLAG IMAGE_FILE_MACHINE_AMD64 | ||
443 | # define GATE_DEBUG_GETFRAME(frame, ctx) do { \ | ||
444 | gate_platform.Win32RtlCaptureContext(&ctx); \ | ||
445 | frame.AddrFrame.Mode = AddrModeFlat; \ | ||
446 | frame.AddrFrame.Offset = (DWORD64)ctx.Rbp; \ | ||
447 | frame.AddrStack.Mode = AddrModeFlat; \ | ||
448 | frame.AddrStack.Offset = (DWORD64)ctx.Rsp; \ | ||
449 | frame.AddrPC.Mode = AddrModeFlat; \ | ||
450 | frame.AddrPC.Offset = (DWORD64)ctx.Rip; \ | ||
451 | } while(0) | ||
452 | # elif (GATE_ARCH == GATE_ARCH_ARM64) | ||
453 | # define MACHINE_FLAG IMAGE_FILE_MACHINE_ARM64 | ||
454 | # define GATE_DEBUG_GETFRAME(frame, ctx) do { \ | ||
455 | gate_platform.Win32RtlCaptureContext(&ctx); \ | ||
456 | frame.AddrFrame.Mode = AddrModeFlat; \ | ||
457 | frame.AddrFrame.Offset = (DWORD64)ctx.Fp; \ | ||
458 | frame.AddrStack.Mode = AddrModeFlat; \ | ||
459 | frame.AddrStack.Offset = (DWORD64)ctx.Sp; \ | ||
460 | frame.AddrPC.Mode = AddrModeFlat; \ | ||
461 | frame.AddrPC.Offset = (DWORD64)ctx.Pc; \ | ||
462 | frame.AddrReturn.Mode = AddrModeFlat; \ | ||
463 | frame.AddrReturn.Offset = (DWORD64)ctx.Lr; \ | ||
464 | } while(0) | ||
465 | # elif (GATE_ARCH == GATE_ARCH_ARM32) | ||
466 | # define MACHINE_FLAG IMAGE_FILE_MACHINE_ARM | ||
467 | # define GATE_DEBUG_GETFRAME(frame, ctx) do { \ | ||
468 | gate_platform.Win32RtlCaptureContext(&ctx); \ | ||
469 | frame.AddrFrame.Mode = AddrModeFlat; \ | ||
470 | frame.AddrFrame.Offset = (DWORD64)ctx.R12; \ | ||
471 | frame.AddrStack.Mode = AddrModeFlat; \ | ||
472 | frame.AddrStack.Offset = (DWORD64)ctx.Sp; \ | ||
473 | frame.AddrPC.Mode = AddrModeFlat; \ | ||
474 | frame.AddrPC.Offset = (DWORD64)ctx.Pc; \ | ||
475 | } while(0) | ||
476 | # elif (GATE_ARCH == GATE_ARCH_X86IA32) | ||
477 | # define MACHINE_FLAG IMAGE_FILE_MACHINE_I386 | ||
478 | # define GATE_DEBUG_GETFRAME(frame, ctx) do { \ | ||
479 | size_t * ptrFrame = 0; \ | ||
480 | size_t ptrStack = 0; \ | ||
481 | _asm { mov ptrFrame, ebp } \ | ||
482 | _asm { mov ptrStack, esp } \ | ||
483 | ctx.Ebp = (DWORD)(size_t)(ptrFrame); \ | ||
484 | ctx.Esp = (DWORD)ptrStack; \ | ||
485 | ctx.Eip = (DWORD)*(ptrFrame + 1); \ | ||
486 | frame.AddrFrame.Mode = AddrModeFlat; \ | ||
487 | frame.AddrFrame.Offset = (DWORD64)ctx.Ebp; \ | ||
488 | frame.AddrStack.Mode = AddrModeFlat; \ | ||
489 | frame.AddrStack.Offset = (DWORD64)ctx.Esp; \ | ||
490 | frame.AddrPC.Mode = AddrModeFlat; \ | ||
491 | frame.AddrPC.Offset = (DWORD64)ctx.Eip; \ | ||
492 | } while(0) | ||
493 | # else | ||
494 | # define GATE_DEBUG_GETFRAME(frame, ctx) do { \ | ||
495 | frame.AddrFrame.Mode = AddrModeFlat; \ | ||
496 | frame.AddrFrame.Offset = (DWORD64)0; \ | ||
497 | frame.AddrStack.Mode = AddrModeFlat; \ | ||
498 | frame.AddrStack.Offset = (DWORD64)0; \ | ||
499 | frame.AddrPC.Mode = AddrModeFlat; \ | ||
500 | frame.AddrPC.Offset = (DWORD64)0; \ | ||
501 | } while(0) | ||
502 | # endif | ||
503 | #elif defined(GATE_COMPILER_GCC) | ||
504 | # define GATE_WINAPI_CPU_CONTEXT CONTEXT | ||
505 | # if defined(GATE_SYS_WIN64) | ||
506 | # define MACHINE_FLAG IMAGE_FILE_MACHINE_AMD64 | ||
507 | # define GATE_DEBUG_GETFRAME(frame, ctx) do { \ | ||
508 | gate_platform.Win32RtlCaptureContext(&ctx); \ | ||
509 | frame.AddrFrame.Mode = AddrModeFlat; \ | ||
510 | frame.AddrFrame.Offset = (DWORD64)ctx.Rbp; \ | ||
511 | frame.AddrStack.Mode = AddrModeFlat; \ | ||
512 | frame.AddrStack.Offset = (DWORD64)ctx.Rsp; \ | ||
513 | frame.AddrPC.Mode = AddrModeFlat; \ | ||
514 | frame.AddrPC.Offset = (DWORD64)ctx.Rip; \ | ||
515 | } while(0) | ||
516 | # else | ||
517 | # define MACHINE_FLAG IMAGE_FILE_MACHINE_I386 | ||
518 | # define GATE_DEBUG_GETFRAME(frame, ctx) do { \ | ||
519 | size_t * ptrFrame = 0; \ | ||
520 | size_t ptrStack = 0; \ | ||
521 | asm ( "movl %%ebp, %0;" : "=r" ( ptrFrame ) ); \ | ||
522 | asm ( "movl %%esp, %0;" : "=r" ( ptrStack ) ); \ | ||
523 | ctx.Ebp = (DWORD)(size_t)(ptrFrame); \ | ||
524 | ctx.Esp = (DWORD)ptrStack; \ | ||
525 | ctx.Eip = (DWORD)*(ptrFrame + 1); \ | ||
526 | frame.AddrFrame.Mode = AddrModeFlat; \ | ||
527 | frame.AddrFrame.Offset = (DWORD64)ctx.Ebp; \ | ||
528 | frame.AddrStack.Mode = AddrModeFlat; \ | ||
529 | frame.AddrStack.Offset = (DWORD64)ctx.Esp; \ | ||
530 | frame.AddrPC.Mode = AddrModeFlat; \ | ||
531 | frame.AddrPC.Offset = (DWORD64)ctx.Eip; \ | ||
532 | } while(0) | ||
533 | # endif | ||
534 | #elif defined(GATE_COMPILER_WATCOM) | ||
535 | # define GATE_WINAPI_CPU_CONTEXT CONTEXT | ||
536 | # if (GATE_ARCH == GATE_ARCH_X86IA32) | ||
537 | # define MACHINE_FLAG IMAGE_FILE_MACHINE_I386 | ||
538 | # define GATE_DEBUG_GETFRAME(frame, ctx) do { \ | ||
539 | size_t * ptrFrame = 0; \ | ||
540 | size_t ptrStack = 0; \ | ||
541 | ctx.Ebp = (DWORD)(size_t)(ptrFrame); \ | ||
542 | ctx.Esp = (DWORD)ptrStack; \ | ||
543 | ctx.Eip = (DWORD)*(ptrFrame + 1); \ | ||
544 | frame.AddrFrame.Mode = AddrModeFlat; \ | ||
545 | frame.AddrFrame.Offset = (DWORD64)ctx.Ebp; \ | ||
546 | frame.AddrStack.Mode = AddrModeFlat; \ | ||
547 | frame.AddrStack.Offset = (DWORD64)ctx.Esp; \ | ||
548 | frame.AddrPC.Mode = AddrModeFlat; \ | ||
549 | frame.AddrPC.Offset = (DWORD64)ctx.Eip; \ | ||
550 | } while(0) | ||
551 | # endif | ||
552 | #elif defined(GATE_COMPILER_TCC) | ||
553 | typedef struct | ||
554 | { | ||
555 | DWORD ControlWord; | ||
556 | DWORD StatusWord; | ||
557 | DWORD TagWord; | ||
558 | DWORD ErrorOffset; | ||
559 | DWORD ErrorSelector; | ||
560 | DWORD DataOffset; | ||
561 | DWORD DataSelector; | ||
562 | BYTE RegisterArea[80]; | ||
563 | DWORD Spare0; | ||
564 | } WIN32_CPU_FLOATING_SAVE_AREA; | ||
565 | |||
566 | typedef struct | ||
567 | { | ||
568 | DWORD ContextFlags; | ||
569 | |||
570 | DWORD Dr0; | ||
571 | DWORD Dr1; | ||
572 | DWORD Dr2; | ||
573 | DWORD Dr3; | ||
574 | DWORD Dr6; | ||
575 | DWORD Dr7; | ||
576 | |||
577 | WIN32_CPU_FLOATING_SAVE_AREA FloatSave; | ||
578 | |||
579 | DWORD SegGs; | ||
580 | DWORD SegFs; | ||
581 | DWORD SegEs; | ||
582 | DWORD SegDs; | ||
583 | |||
584 | DWORD Edi; | ||
585 | DWORD Esi; | ||
586 | DWORD Ebx; | ||
587 | DWORD Edx; | ||
588 | DWORD Ecx; | ||
589 | DWORD Eax; | ||
590 | |||
591 | DWORD Ebp; | ||
592 | DWORD Eip; | ||
593 | DWORD SegCs; | ||
594 | DWORD EFlags; | ||
595 | DWORD Esp; | ||
596 | DWORD SegSs; | ||
597 | |||
598 | BYTE ExtendedRegisters[512]; | ||
599 | } WIN32_CPU_CONTEXT; | ||
600 | |||
601 | #define GATE_WINAPI_CPU_CONTEXT WIN32_CPU_CONTEXT | ||
602 | # if (GATE_ARCH == GATE_ARCH_X86IA32) | ||
603 | # define MACHINE_FLAG IMAGE_FILE_MACHINE_I386 | ||
604 | # define GATE_DEBUG_GETFRAME(frame, ctx) do { \ | ||
605 | size_t * ptrFrame = 0; \ | ||
606 | size_t ptrStack = 0; \ | ||
607 | ctx.Ebp = (DWORD)(size_t)(ptrFrame); \ | ||
608 | ctx.Esp = (DWORD)ptrStack; \ | ||
609 | ctx.Eip = (DWORD)*(ptrFrame + 1); \ | ||
610 | frame.AddrFrame.Mode = AddrModeFlat; \ | ||
611 | frame.AddrFrame.Offset = (DWORD64)ctx.Ebp; \ | ||
612 | frame.AddrStack.Mode = AddrModeFlat; \ | ||
613 | frame.AddrStack.Offset = (DWORD64)ctx.Esp; \ | ||
614 | frame.AddrPC.Mode = AddrModeFlat; \ | ||
615 | frame.AddrPC.Offset = (DWORD64)ctx.Eip; \ | ||
616 | } while(0) | ||
617 | # endif | ||
618 | |||
619 | #endif | ||
620 | |||
621 | |||
622 | gate_result_t gate_callstack_trace(gate_callstack_address_t* addresses, gate_size_t addresses_count, gate_size_t* addresses_used) | ||
623 | { | ||
624 | gate_result_t ret; | ||
625 | HANDLE hThread = GetCurrentThread(); | ||
626 | HANDLE hProcess = NULL; | ||
627 | STACKFRAME64 frame; | ||
628 | GATE_WINAPI_CPU_CONTEXT ctx; | ||
629 | |||
630 | DWORD dwMachineFlag = MACHINE_FLAG; | ||
631 | LPCONTEXT pctx = NULL; | ||
632 | gate_size_t frames_found = 0; | ||
633 | BOOL symcleanup_required = FALSE; | ||
634 | |||
635 | do | ||
636 | { | ||
637 | if (!gate_callstack_init()) | ||
638 | { | ||
639 | ret = GATE_RESULT_NOTSUPPORTED; | ||
640 | break; | ||
641 | } | ||
642 | |||
643 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId()); | ||
644 | if (hProcess == NULL) | ||
645 | { | ||
646 | ret = GATE_RESULT_OUTOFRESOURCES; | ||
647 | break; | ||
648 | } | ||
649 | |||
650 | symcleanup_required = SymInitialize(hProcess, NULL, TRUE); | ||
651 | |||
652 | gate_mem_clear(&frame, sizeof(frame)); | ||
653 | gate_mem_clear(&ctx, sizeof(ctx)); | ||
654 | |||
655 | GATE_DEBUG_GETFRAME(frame, ctx); | ||
656 | |||
657 | #if (GATE_ARCH == GATE_ARCH_ARM64) | ||
658 | dwMachineFlag = IMAGE_FILE_MACHINE_ARM64; | ||
659 | pctx = &ctx; | ||
660 | #elif (GATE_ARCH == GATE_ARCH_X86X64) | ||
661 | dwMachineFlag = IMAGE_FILE_MACHINE_AMD64; | ||
662 | pctx = &ctx; | ||
663 | #endif | ||
664 | if (!StackWalk64(dwMachineFlag, hProcess, hThread, &frame, pctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) | ||
665 | { | ||
666 | ret = GATE_RESULT_FAILED; | ||
667 | break; | ||
668 | } | ||
669 | ret = GATE_RESULT_OK; | ||
670 | while (addresses_count-- != 0) | ||
671 | { | ||
672 | if (StackWalk64(dwMachineFlag, hProcess, hThread, &frame, pctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) | ||
673 | { | ||
674 | *addresses = (gate_callstack_address_t)(gate_uintptr_t)frame.AddrPC.Offset; | ||
675 | ++frames_found; | ||
676 | ++addresses; | ||
677 | } | ||
678 | else | ||
679 | { | ||
680 | break; | ||
681 | } | ||
682 | } | ||
683 | if (addresses_used != 0) | ||
684 | { | ||
685 | *addresses_used = frames_found; | ||
686 | } | ||
687 | } while (0); | ||
688 | |||
689 | if (symcleanup_required) | ||
690 | { | ||
691 | SymCleanup(hProcess); | ||
692 | } | ||
693 | |||
694 | if (hProcess != NULL) | ||
695 | { | ||
696 | CloseHandle(hProcess); | ||
697 | } | ||
698 | |||
699 | return ret; | ||
700 | } | ||
701 | gate_result_t gate_callstack_print(gate_callstack_address_t address, char* buffer, gate_size_t buffer_length, gate_size_t* buffer_used) | ||
702 | { | ||
703 | gate_result_t ret = GATE_RESULT_FAILED; | ||
704 | HANDLE hProcess = NULL; | ||
705 | IMAGEHLP_MODULE64 mod64; | ||
706 | DWORD64 dwAddr; | ||
707 | DWORD64 dwDisp = 0; | ||
708 | char bufSym[sizeof(IMAGEHLP_SYMBOL64) + MAX_SYM_NAME]; | ||
709 | IMAGEHLP_SYMBOL64* pSym = (IMAGEHLP_SYMBOL64*)&bufSym[0]; | ||
710 | gate_size_t len; | ||
711 | |||
712 | do | ||
713 | { | ||
714 | if (!gate_callstack_init()) | ||
715 | { | ||
716 | ret = GATE_RESULT_NOTSUPPORTED; | ||
717 | break; | ||
718 | } | ||
719 | |||
720 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId()); | ||
721 | if (hProcess == NULL) | ||
722 | { | ||
723 | ret = GATE_RESULT_OUTOFRESOURCES; | ||
724 | break; | ||
725 | } | ||
726 | |||
727 | gate_mem_clear(&mod64, sizeof(mod64)); | ||
728 | mod64.SizeOfStruct = sizeof(mod64); | ||
729 | dwAddr = (DWORD64)(gate_uintptr_t)address; | ||
730 | SymGetModuleInfo64(hProcess, dwAddr, &mod64); | ||
731 | gate_mem_clear(pSym, sizeof(IMAGEHLP_SYMBOL64) + MAX_SYM_NAME); | ||
732 | pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); | ||
733 | pSym->MaxNameLength = MAX_SYM_NAME; | ||
734 | |||
735 | if (SymGetSymFromAddr64(hProcess, dwAddr, &dwDisp, pSym)) | ||
736 | { | ||
737 | len = gate_str_print_text(buffer, buffer_length, pSym->Name, gate_str_length(pSym->Name)); | ||
738 | if (buffer_used != NULL) | ||
739 | { | ||
740 | *buffer_used = len; | ||
741 | } | ||
742 | ret = GATE_RESULT_OK; | ||
743 | } | ||
744 | else | ||
745 | { | ||
746 | gate_str_print_hex_uint64(buffer, buffer_length, (gate_uint64_t)(gate_uintptr_t)address, false); | ||
747 | ret = GATE_RESULT_OK_PARTIAL; | ||
748 | } | ||
749 | } while (0); | ||
750 | |||
751 | if (hProcess != NULL) | ||
752 | { | ||
753 | CloseHandle(hProcess); | ||
754 | } | ||
755 | |||
756 | return ret; | ||
757 | } | ||
758 | |||
759 | #endif /* GATE_CALLSTACKS_WIN32_DBG_IMPL */ | ||
760 | |||
761 | |||
762 | #ifdef GATE_CALLSTACKS_WIN32_CALLSTACK_IMPL | ||
763 | |||
764 | #include "gate/platform/windows/win32callstack.h" | ||
765 | |||
766 | #include "gate/platforms.h" | ||
767 | #include <windows.h> | ||
768 | |||
769 | |||
770 | #if defined(GATE_COMPILE_ASM_SUPPORT) | ||
771 | |||
772 | #ifndef MEM_COMMIT | ||
773 | #define MEM_COMMIT 0x1000 | ||
774 | #endif | ||
775 | |||
776 | #ifndef PAGE_READWRITE | ||
777 | #define PAGE_READWRITE 0x04 | ||
778 | #endif | ||
779 | |||
780 | #ifndef PAGE_EXECUTE_READ | ||
781 | #define PAGE_EXECUTE_READ 0x20 | ||
782 | #endif | ||
783 | |||
784 | #ifndef PAGE_EXECUTE_READWRITE | ||
785 | #define PAGE_EXECUTE_READWRITE 0x40 | ||
786 | #endif | ||
787 | |||
788 | #ifndef MEM_RELEASE | ||
789 | #define MEM_RELEASE 0x8000 | ||
790 | #endif | ||
791 | |||
792 | gate_result_t gate_callstack_create(gate_size_t* ptr_stacksize, void** ptr_callstack) | ||
793 | { | ||
794 | gate_result_t ret = GATE_RESULT_FAILED; | ||
795 | LPVOID stack_buffer = NULL; | ||
796 | DWORD old_protect = 0; | ||
797 | gate_size_t stacksize; | ||
798 | do | ||
799 | { | ||
800 | if (!ptr_callstack || !ptr_stacksize) | ||
801 | { | ||
802 | ret = GATE_RESULT_INVALIDARG; | ||
803 | break; | ||
804 | } | ||
805 | stacksize = *ptr_stacksize; | ||
806 | stacksize &= ~((gate_size_t)0xff); | ||
807 | if (stacksize == 0) | ||
808 | { | ||
809 | stacksize = 256 * 1024; | ||
810 | } | ||
811 | if (stacksize < 4096) | ||
812 | { | ||
813 | stacksize = 4096; | ||
814 | } | ||
815 | stack_buffer = VirtualAlloc(NULL, stacksize, MEM_COMMIT, PAGE_READWRITE); | ||
816 | if (NULL == stack_buffer) | ||
817 | { | ||
818 | break; | ||
819 | } | ||
820 | if (!VirtualProtect(stack_buffer, stacksize, PAGE_EXECUTE_READWRITE, &old_protect)) | ||
821 | { | ||
822 | VirtualFree(stack_buffer, 0, MEM_RELEASE); | ||
823 | } | ||
824 | |||
825 | ret = GATE_RESULT_OK; | ||
826 | *ptr_stacksize = stacksize; | ||
827 | *ptr_callstack = stack_buffer; | ||
828 | |||
829 | } while (0); | ||
830 | return ret; | ||
831 | } | ||
832 | gate_result_t gate_callstack_destroy(void* ptr_callstack, gate_size_t stacksize) | ||
833 | { | ||
834 | gate_result_t ret = GATE_RESULT_FAILED; | ||
835 | if (ptr_callstack) | ||
836 | { | ||
837 | if (VirtualFree((LPVOID)ptr_callstack, 0, MEM_RELEASE)) | ||
838 | { | ||
839 | ret = GATE_RESULT_OK; | ||
840 | } | ||
841 | } | ||
842 | return ret; | ||
843 | } | ||
844 | |||
845 | |||
846 | gate_result_t gate_callstack_run(void* ptr_callstack, gate_size_t stacksize, | ||
847 | gate_callstack_context_t* ptr_caller_ctx_to_save, | ||
848 | gate_entrypoint_t entry_func, void* param, | ||
849 | gate_result_t* ptr_returnvalue) | ||
850 | { | ||
851 | gate_result_t ret = GATE_RESULT_FAILED; | ||
852 | gate_size_t stack_addr = (gate_size_t)ptr_callstack; | ||
853 | void* stack_top; | ||
854 | gate_callstack_context_t context = GATE_INIT_EMPTY; | ||
855 | void* entry_ret = NULL; | ||
856 | |||
857 | if (NULL == ptr_caller_ctx_to_save) | ||
858 | { | ||
859 | ptr_caller_ctx_to_save = &context; | ||
860 | } | ||
861 | |||
862 | stack_addr += (stacksize - 4); | ||
863 | stack_addr -= (stack_addr & 0x0f); | ||
864 | stack_top = (void*)stack_addr; | ||
865 | |||
866 | #if !defined(GATE_SYS_WINCE) | ||
867 | entry_ret = gate_win32_callstack_create(stack_top, ptr_caller_ctx_to_save, entry_func, param); | ||
868 | ret = GATE_RESULT_OK; | ||
869 | #endif | ||
870 | if (ptr_returnvalue) | ||
871 | { | ||
872 | *ptr_returnvalue = (gate_result_t)(gate_intptr_t)entry_ret; | ||
873 | } | ||
874 | return ret; | ||
875 | } | ||
876 | |||
877 | gate_result_t gate_callstack_switch(gate_callstack_context_t* current_to_save, | ||
878 | gate_callstack_context_t* next_to_load) | ||
879 | { | ||
880 | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | ||
881 | #if !defined(GATE_SYS_WINCE) | ||
882 | if (NULL == gate_win32_callstack_switch(current_to_save, next_to_load)) | ||
883 | { | ||
884 | ret = GATE_RESULT_FAILED; | ||
885 | } | ||
886 | else | ||
887 | { | ||
888 | ret = GATE_RESULT_OK; | ||
889 | } | ||
890 | #endif | ||
891 | return ret; | ||
892 | } | ||
893 | |||
894 | #else /* GATE_COMPILE_ASM_SUPPORT */ | ||
895 | |||
896 | /* use FIBERs if no native ASM support is present */ | ||
897 | |||
898 | typedef struct gate_callstack_fiber_class | ||
899 | { | ||
900 | LPVOID fiber; | ||
901 | LPVOID parent; | ||
902 | gate_entrypoint_t entrypoint; | ||
903 | void* param; | ||
904 | gate_result_t result; | ||
905 | |||
906 | } gate_callstack_fiber_t; | ||
907 | |||
908 | |||
909 | static VOID WINAPI gate_callstack_fiber_dispatcher(LPVOID lpFiberParameter) | ||
910 | { | ||
911 | gate_callstack_fiber_t* ptr_fiber = (gate_callstack_fiber_t*)lpFiberParameter; | ||
912 | if (ptr_fiber && ptr_fiber->entrypoint) | ||
913 | { | ||
914 | ptr_fiber->result = ptr_fiber->entrypoint(ptr_fiber->param); | ||
915 | gate_win32_fibers()->Win32SwitchToFiber(ptr_fiber->parent); | ||
916 | } | ||
917 | } | ||
918 | |||
919 | |||
920 | gate_result_t gate_callstack_create(gate_size_t* ptr_stacksize, void** ptr_callstack) | ||
921 | { | ||
922 | gate_result_t ret = GATE_RESULT_FAILED; | ||
923 | gate_callstack_fiber_t* ptr_fiber = NULL; | ||
924 | gate_size_t stacksize = 0; | ||
925 | gate_win32_fibers_t* fibers = NULL; | ||
926 | |||
927 | do | ||
928 | { | ||
929 | if (!ptr_callstack || !ptr_stacksize) | ||
930 | { | ||
931 | ret = GATE_RESULT_INVALIDARG; | ||
932 | break; | ||
933 | } | ||
934 | stacksize = *ptr_stacksize; | ||
935 | stacksize &= ~((gate_size_t)0xff); | ||
936 | if (stacksize == 0) | ||
937 | { | ||
938 | stacksize = 256 * 1024; | ||
939 | } | ||
940 | if (stacksize < 4096) | ||
941 | { | ||
942 | stacksize = 4096; | ||
943 | } | ||
944 | |||
945 | fibers = gate_win32_fibers(); | ||
946 | |||
947 | if (!fibers) | ||
948 | { | ||
949 | ret = GATE_RESULT_NOTSUPPORTED; | ||
950 | break; | ||
951 | } | ||
952 | |||
953 | ptr_fiber = (gate_callstack_fiber_t*)gate_mem_alloc(sizeof(gate_callstack_fiber_t)); | ||
954 | if (!ptr_fiber) | ||
955 | { | ||
956 | ret = GATE_RESULT_OUTOFMEMORY; | ||
957 | break; | ||
958 | } | ||
959 | gate_mem_clear(ptr_fiber, sizeof(gate_callstack_fiber_t)); | ||
960 | |||
961 | ptr_fiber->fiber = fibers->Win32CreateFiber(stacksize, &gate_callstack_fiber_dispatcher, ptr_fiber); | ||
962 | if (ptr_fiber == NULL) | ||
963 | { | ||
964 | ret = gate_platform_print_last_error(NULL, 0); | ||
965 | break; | ||
966 | } | ||
967 | |||
968 | *ptr_callstack = (void*)ptr_fiber; | ||
969 | *ptr_stacksize = stacksize; | ||
970 | ptr_fiber = NULL; | ||
971 | ret = GATE_RESULT_OK; | ||
972 | } while (0); | ||
973 | |||
974 | if (ptr_fiber) | ||
975 | { | ||
976 | gate_mem_dealloc(ptr_fiber); | ||
977 | } | ||
978 | return ret; | ||
979 | } | ||
980 | gate_result_t gate_callstack_destroy(void* ptr_callstack, gate_size_t stacksize) | ||
981 | { | ||
982 | gate_result_t ret = GATE_RESULT_FAILED; | ||
983 | gate_callstack_fiber_t* ptr_fiber = (gate_callstack_fiber_t*)ptr_callstack; | ||
984 | |||
985 | GATE_UNUSED_ARG(stacksize); | ||
986 | |||
987 | if (ptr_fiber) | ||
988 | { | ||
989 | gate_win32_fibers_t* fibers = gate_win32_fibers(); | ||
990 | if (fibers) | ||
991 | { | ||
992 | fibers->Win32DeleteFiber(ptr_fiber->fiber); | ||
993 | } | ||
994 | gate_mem_dealloc(ptr_fiber); | ||
995 | ret = GATE_RESULT_OK; | ||
996 | } | ||
997 | return ret; | ||
998 | } | ||
999 | |||
1000 | |||
1001 | gate_result_t gate_callstack_run(void* ptr_callstack, gate_size_t stacksize, | ||
1002 | gate_callstack_context_t* ptr_caller_ctx_to_save, | ||
1003 | gate_entrypoint_t entry_func, void* param, | ||
1004 | gate_result_t* ptr_returnvalue) | ||
1005 | { | ||
1006 | gate_result_t ret = GATE_RESULT_FAILED; | ||
1007 | gate_callstack_fiber_t* ptr_fiber = (gate_callstack_fiber_t*)ptr_callstack; | ||
1008 | gate_callstack_context_t local_context = GATE_INIT_EMPTY; | ||
1009 | LPVOID current_fiber = NULL; | ||
1010 | gate_bool_t was_fiber = false; | ||
1011 | |||
1012 | GATE_UNUSED_ARG(stacksize); | ||
1013 | |||
1014 | do | ||
1015 | { | ||
1016 | gate_win32_fibers_t* fibers = gate_win32_fibers(); | ||
1017 | if (!fibers) | ||
1018 | { | ||
1019 | break; | ||
1020 | } | ||
1021 | |||
1022 | if (NULL == ptr_caller_ctx_to_save) | ||
1023 | { | ||
1024 | ptr_caller_ctx_to_save = &local_context; | ||
1025 | } | ||
1026 | |||
1027 | ptr_fiber->entrypoint = entry_func; | ||
1028 | ptr_fiber->param = param; | ||
1029 | |||
1030 | current_fiber = fibers->Win32ConvertThreadToFiber(NULL); | ||
1031 | if (current_fiber != NULL) | ||
1032 | { | ||
1033 | /* previously a thread, now a fiber */ | ||
1034 | was_fiber = false; | ||
1035 | } | ||
1036 | else | ||
1037 | { | ||
1038 | /* was already a fiber, retrieve its handle*/ | ||
1039 | was_fiber = true; | ||
1040 | current_fiber = fibers->Win32GetCurrentFiber(); | ||
1041 | if (NULL == current_fiber) | ||
1042 | { | ||
1043 | ret = GATE_RESULT_OUTOFRESOURCES; | ||
1044 | break; | ||
1045 | } | ||
1046 | } | ||
1047 | ptr_fiber->parent = current_fiber; | ||
1048 | ptr_caller_ctx_to_save->store[0] = current_fiber; | ||
1049 | |||
1050 | fibers->Win32SwitchToFiber(ptr_fiber->fiber); | ||
1051 | |||
1052 | ptr_fiber->parent = NULL; | ||
1053 | |||
1054 | if (ptr_returnvalue) | ||
1055 | { | ||
1056 | *ptr_returnvalue = ptr_fiber->result; | ||
1057 | } | ||
1058 | |||
1059 | if (!was_fiber) | ||
1060 | { | ||
1061 | if (fibers->Win32ConvertFiberToThread) | ||
1062 | { | ||
1063 | fibers->Win32ConvertFiberToThread(); | ||
1064 | } | ||
1065 | } | ||
1066 | ret = GATE_RESULT_OK; | ||
1067 | } while (0); | ||
1068 | |||
1069 | return ret; | ||
1070 | } | ||
1071 | |||
1072 | gate_result_t gate_callstack_switch(gate_callstack_context_t* current_to_save, | ||
1073 | gate_callstack_context_t* next_to_load) | ||
1074 | { | ||
1075 | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | ||
1076 | #if !defined(GATE_SYS_WINCE) | ||
1077 | gate_win32_fibers_t* fibers = gate_win32_fibers(); | ||
1078 | if (fibers->Win32SwitchToFiber) | ||
1079 | { | ||
1080 | PVOID current_fiber = fibers->Win32GetCurrentFiber(); | ||
1081 | PVOID next_fiber = next_to_load->store[0]; | ||
1082 | current_to_save->store[0] = current_fiber; | ||
1083 | fibers->Win32SwitchToFiber(next_fiber); | ||
1084 | ret = GATE_RESULT_OK; | ||
1085 | } | ||
1086 | #endif | ||
1087 | return ret; | ||
1088 | } | ||
1089 | |||
1090 | |||
1091 | #endif /* GATE_COMPILE_ASM_SUPPORT */ | ||
1092 | |||
1093 | |||
1094 | #endif /* GATE_CALLSTACKS_WIN32_CALLSTACK_IMPL */ | ||
1095 | |||
1096 | |||
1097 | |||
1098 | |||
1099 | |||
1100 | |||
1101 | #if defined(GATE_CALLSTACKS_POSIX_IMPL) | ||
1102 | |||
1103 | #include <stdlib.h> | ||
1104 | #include <dlfcn.h> | ||
1105 | #include <stdio.h> | ||
1106 | #include <setjmp.h> | ||
1107 | #include <signal.h> | ||
1108 | #include <sys/mman.h> | ||
1109 | #include "gate/platform/posix/posixcallstack.h" | ||
1110 | #include "gate/platform/posix/posixucontext.h" | ||
1111 | #include "gate/debugging.h" | ||
1112 | |||
1113 | #if defined(HAVE_BACKTRACE) | ||
1114 | #include <execinfo.h> | ||
1115 | #endif | ||
1116 | |||
1117 | #define DEFAULT_STACK_SIZE (1024 * 1024) | ||
1118 | #define MINMUM_STACK_SIZE (4 * 1024) | ||
1119 | |||
1120 | #if defined(GATE_SYS_FREEBSD) | ||
1121 | typedef size_t backtrace_length_t; | ||
1122 | #else | ||
1123 | typedef int backtrace_length_t; | ||
1124 | #endif | ||
1125 | |||
1126 | typedef backtrace_length_t(*backtrace_func_t)(void** buffer, backtrace_length_t size); | ||
1127 | typedef char** (*backtrace_symbols_func_t)(void* const* buffer, backtrace_length_t size); | ||
1128 | |||
1129 | static backtrace_func_t volatile backtrace_func = NULL; | ||
1130 | static backtrace_symbols_func_t volatile backtrace_symbols_func = NULL; | ||
1131 | |||
1132 | |||
1133 | #if defined(HAVE_BACKTRACE) | ||
1134 | |||
1135 | 2 | static gate_bool_t load_backtrace_functions() | |
1136 | { | ||
1137 | 2 | backtrace_func = &backtrace; | |
1138 | 2 | backtrace_symbols_func = &backtrace_symbols; | |
1139 | 2 | return true; | |
1140 | } | ||
1141 | |||
1142 | #else | ||
1143 | |||
1144 | static void* volatile execinfo_symbols = NULL; | ||
1145 | |||
1146 | static void close_execinfo_atexit() | ||
1147 | { | ||
1148 | if (NULL != execinfo_symbols) | ||
1149 | { | ||
1150 | void* const lib = execinfo_symbols; | ||
1151 | execinfo_symbols = NULL; | ||
1152 | dlclose(lib); | ||
1153 | } | ||
1154 | } | ||
1155 | |||
1156 | static void load_backtrace_from_libexecinfo() | ||
1157 | { | ||
1158 | if (execinfo_symbols == NULL) | ||
1159 | { | ||
1160 | execinfo_symbols = gate_posix_dlopen("libexecinfo.so", RTLD_GLOBAL); | ||
1161 | if (NULL != execinfo_symbols) | ||
1162 | { | ||
1163 | gate_platform_atexit(&close_execinfo_atexit); | ||
1164 | } | ||
1165 | } | ||
1166 | |||
1167 | if (execinfo_symbols != NULL) | ||
1168 | { | ||
1169 | backtrace_func = dlsym(execinfo_symbols, "backtrace"); | ||
1170 | backtrace_symbols_func = dlsym(execinfo_symbols, "backtrace_symbols"); | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | static gate_bool_t load_backtrace_functions() | ||
1175 | { | ||
1176 | if (!backtrace_func || backtrace_symbols_func) | ||
1177 | { | ||
1178 | /* lookup in global function table: */ | ||
1179 | backtrace_func = gate_posix_global_sym("backtrace"); | ||
1180 | backtrace_symbols_func = gate_posix_global_sym("backtrace_symbols"); | ||
1181 | |||
1182 | if ((NULL == backtrace_func) || (NULL == backtrace_symbols_func)) | ||
1183 | { | ||
1184 | load_backtrace_from_libexecinfo(); | ||
1185 | } | ||
1186 | } | ||
1187 | return backtrace_func && backtrace_symbols_func; | ||
1188 | } | ||
1189 | |||
1190 | #endif | ||
1191 | |||
1192 | |||
1193 | 1 | gate_result_t gate_callstack_trace(gate_callstack_address_t* addresses, gate_size_t addresses_count, gate_size_t* addresses_used) | |
1194 | { | ||
1195 | 1 | gate_result_t ret = GATE_RESULT_OK; | |
1196 | void* stackaddress[1024]; | ||
1197 | backtrace_length_t index; | ||
1198 | backtrace_length_t stackaddress_count; | ||
1199 | |||
1200 | 1 | load_backtrace_functions(); | |
1201 | |||
1202 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!backtrace_func) |
1203 | { | ||
1204 | ✗ | GATE_DEBUG_TRACE("backtrace() not supported"); | |
1205 | ✗ | return GATE_RESULT_NOTSUPPORTED; | |
1206 | } | ||
1207 | |||
1208 | 1 | stackaddress_count = backtrace_func(stackaddress, sizeof(stackaddress) / sizeof(stackaddress[0])); | |
1209 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (stackaddress_count > 0) |
1210 | { | ||
1211 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (stackaddress_count > (backtrace_length_t)addresses_count) |
1212 | { | ||
1213 | ✗ | stackaddress_count = (backtrace_length_t)addresses_count; | |
1214 | } | ||
1215 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 times.
|
13 | for (index = 0; index != stackaddress_count; ++index) |
1216 | { | ||
1217 | 12 | addresses[index] = stackaddress[index]; | |
1218 | } | ||
1219 | 1 | *addresses_used = (gate_size_t)stackaddress_count; | |
1220 | 1 | ret = GATE_RESULT_OK; | |
1221 | } | ||
1222 | else | ||
1223 | { | ||
1224 | ✗ | *addresses_used = 0; | |
1225 | } | ||
1226 | 1 | return ret; | |
1227 | } | ||
1228 | |||
1229 | 1 | gate_result_t gate_callstack_print(gate_callstack_address_t address, char* buffer, gate_size_t buffer_length, gate_size_t* buffer_used) | |
1230 | { | ||
1231 | gate_size_t len; | ||
1232 | char** names; | ||
1233 | |||
1234 | 1 | load_backtrace_functions(); | |
1235 | |||
1236 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (backtrace_symbols_func == NULL) |
1237 | { | ||
1238 | ✗ | return GATE_RESULT_NOTSUPPORTED; | |
1239 | } | ||
1240 | |||
1241 | 1 | names = backtrace_symbols_func((void**)&address, 1); | |
1242 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (names == NULL) |
1243 | { | ||
1244 | ✗ | return GATE_RESULT_FAILED; | |
1245 | } | ||
1246 | |||
1247 | 1 | len = gate_str_print_text(buffer, buffer_length, names[0], gate_str_length(names[0])); | |
1248 | 1 | free(names); | |
1249 | 1 | buffer[len] = 0; | |
1250 | 1 | *buffer_used = len; | |
1251 | 1 | return GATE_RESULT_OK; | |
1252 | } | ||
1253 | |||
1254 | #define GATE_CALLSTACK_MALLOC 1 | ||
1255 | |||
1256 | 6 | static void check_stack_size(gate_size_t* ptr_stacksize) | |
1257 | { | ||
1258 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
|
6 | if (*ptr_stacksize == 0) |
1259 | { | ||
1260 | 1 | *ptr_stacksize = DEFAULT_STACK_SIZE; | |
1261 | } | ||
1262 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (*ptr_stacksize < MINMUM_STACK_SIZE) |
1263 | { | ||
1264 | ✗ | *ptr_stacksize = MINMUM_STACK_SIZE; | |
1265 | } | ||
1266 | /* apply 32-bit maximum and 16-bit alignment */ | ||
1267 | 6 | *ptr_stacksize &= 0xfffffff0; | |
1268 | 6 | } | |
1269 | |||
1270 | 2 | gate_result_t gate_callstack_create(gate_size_t* ptr_stacksize, void** ptr_callstack) | |
1271 | { | ||
1272 | void* ptr; | ||
1273 | gate_size_t stacksize; | ||
1274 | |||
1275 | 2 | check_stack_size(ptr_stacksize); | |
1276 | 2 | stacksize = *ptr_stacksize; | |
1277 | |||
1278 | #if defined(GATE_CALLSTACK_MALLOC) | ||
1279 | 2 | ptr = gate_mem_alloc(stacksize); | |
1280 | #else | ||
1281 | ptr = mmap(NULL, stacksize, PROT_READ | PROT_WRITE /*| PROT_EXEC*/, | ||
1282 | MAP_PRIVATE | MAP_ANONYMOUS /*| MAP_GROWSDOWN*/ | MAP_STACK, -1, 0); | ||
1283 | if (ptr == MAP_FAILED) | ||
1284 | { | ||
1285 | return GATE_RESULT_FAILED; | ||
1286 | } | ||
1287 | #endif | ||
1288 | |||
1289 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (ptr_callstack) |
1290 | { | ||
1291 | 2 | *ptr_callstack = ptr; | |
1292 | } | ||
1293 | else | ||
1294 | { | ||
1295 | ✗ | gate_callstack_destroy(ptr, stacksize); | |
1296 | } | ||
1297 | 2 | return GATE_RESULT_OK; | |
1298 | } | ||
1299 | |||
1300 | 2 | gate_result_t gate_callstack_destroy(void* ptr_callstack, gate_size_t stacksize) | |
1301 | { | ||
1302 | 2 | check_stack_size(&stacksize); | |
1303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!ptr_callstack) |
1304 | { | ||
1305 | ✗ | return GATE_RESULT_INVALIDARG; | |
1306 | } | ||
1307 | #if defined(GATE_CALLSTACK_MALLOC) | ||
1308 | 2 | gate_mem_dealloc(ptr_callstack); | |
1309 | #else | ||
1310 | if (0 == munmap(ptr_callstack, stacksize)) | ||
1311 | { | ||
1312 | return GATE_RESULT_OK; | ||
1313 | } | ||
1314 | else | ||
1315 | { | ||
1316 | return GATE_RESULT_FAILED; | ||
1317 | } | ||
1318 | #endif | ||
1319 | 2 | return GATE_RESULT_OK; | |
1320 | } | ||
1321 | |||
1322 | typedef struct gate_callstack_session_class | ||
1323 | { | ||
1324 | gate_entrypoint_t entry_func; | ||
1325 | void* param; | ||
1326 | gate_result_t* ptr_returnvalue; | ||
1327 | gate_callstack_context_t* parent_context; | ||
1328 | } gate_callstack_session_t; | ||
1329 | |||
1330 | union gate_callstack_entry_dispatcher_args | ||
1331 | { | ||
1332 | gate_callstack_session_t* session; | ||
1333 | int args[4]; | ||
1334 | }; | ||
1335 | |||
1336 | 2 | static void gate_callstack_entry_dispatcher(int a0, int a1, int a2, int a3) | |
1337 | { | ||
1338 | union gate_callstack_entry_dispatcher_args args; | ||
1339 | gate_result_t result; | ||
1340 | gate_callstack_context_t dummy_context; | ||
1341 | |||
1342 | 2 | args.args[0] = a0; | |
1343 | 2 | args.args[1] = a1; | |
1344 | 2 | args.args[2] = a2; | |
1345 | 2 | args.args[3] = a3; | |
1346 | 2 | result = args.session->entry_func(args.session->param); | |
1347 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (args.session->ptr_returnvalue) |
1348 | { | ||
1349 | 1 | *args.session->ptr_returnvalue = result; | |
1350 | } | ||
1351 | 1 | gate_posix_uctx_set(args.session->parent_context); | |
1352 | ✗ | } | |
1353 | |||
1354 | 2 | gate_result_t gate_callstack_run(void* ptr_callstack, gate_size_t stacksize, | |
1355 | gate_callstack_context_t* ptr_caller_ctx_to_save, | ||
1356 | gate_entrypoint_t entry_func, void* param, | ||
1357 | gate_result_t* ptr_returnvalue) | ||
1358 | { | ||
1359 | 2 | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | |
1360 | 2 | gate_size_t stack_addr = (gate_size_t)ptr_callstack; | |
1361 | void* stack_top; | ||
1362 | 2 | gate_callstack_context_t context = GATE_INIT_EMPTY; | |
1363 | 2 | gate_callstack_context_t new_stack_context = GATE_INIT_EMPTY; | |
1364 | void* entry_ret; | ||
1365 | gate_callstack_session_t session; | ||
1366 | union gate_callstack_entry_dispatcher_args disp_args; | ||
1367 | |||
1368 | 2 | check_stack_size(&stacksize); | |
1369 | |||
1370 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (NULL == ptr_caller_ctx_to_save) |
1371 | { | ||
1372 | 1 | ptr_caller_ctx_to_save = &context; | |
1373 | } | ||
1374 | |||
1375 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (gate_posix_callstack_supported()) |
1376 | { | ||
1377 | ✗ | stack_addr += (stacksize - 4); | |
1378 | ✗ | stack_addr -= (stack_addr & 0x0f); | |
1379 | ✗ | stack_top = (void*)stack_addr; | |
1380 | |||
1381 | ✗ | entry_ret = gate_posix_callstack_create(stack_top, ptr_caller_ctx_to_save, entry_func, param); | |
1382 | ✗ | ret = GATE_RESULT_OK; | |
1383 | ✗ | if (ptr_returnvalue) | |
1384 | { | ||
1385 | ✗ | *ptr_returnvalue = (gate_result_t)(gate_intptr_t)entry_ret; | |
1386 | } | ||
1387 | } | ||
1388 | else | ||
1389 | { | ||
1390 | do | ||
1391 | { | ||
1392 | 2 | ret = gate_posix_uctx_init(); | |
1393 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | GATE_BREAK_IF_FAILED(ret); |
1394 | |||
1395 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (0 != gate_posix_uctx_get(&new_stack_context)) |
1396 | { | ||
1397 | ✗ | ret = GATE_RESULT_FAILED; | |
1398 | ✗ | break; | |
1399 | } | ||
1400 | 2 | gate_posix_uctx_setup(&new_stack_context, ptr_callstack, stacksize); | |
1401 | 2 | session.entry_func = entry_func; | |
1402 | 2 | session.param = param; | |
1403 | 2 | session.ptr_returnvalue = ptr_returnvalue; | |
1404 | 2 | session.parent_context = ptr_caller_ctx_to_save; | |
1405 | 2 | disp_args.session = &session; | |
1406 | 2 | gate_posix_uctx_make(&new_stack_context, &gate_callstack_entry_dispatcher, | |
1407 | disp_args.args[0], disp_args.args[1], disp_args.args[2], disp_args.args[3]); | ||
1408 | 2 | gate_posix_uctx_swap(ptr_caller_ctx_to_save, &new_stack_context); | |
1409 | |||
1410 | 2 | ret = GATE_RESULT_OK; | |
1411 | } while (0); | ||
1412 | } | ||
1413 | 2 | return ret; | |
1414 | } | ||
1415 | |||
1416 | 1 | gate_result_t gate_callstack_switch(gate_callstack_context_t* current_to_save, gate_callstack_context_t* next_to_load) | |
1417 | { | ||
1418 | 1 | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | |
1419 | |||
1420 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (gate_posix_callstack_supported()) |
1421 | { | ||
1422 | ✗ | if (NULL == gate_posix_callstack_switch(current_to_save, next_to_load)) | |
1423 | { | ||
1424 | ✗ | ret = GATE_RESULT_FAILED; | |
1425 | } | ||
1426 | else | ||
1427 | { | ||
1428 | ✗ | ret = GATE_RESULT_OK; | |
1429 | } | ||
1430 | } | ||
1431 | else | ||
1432 | { | ||
1433 | 1 | gate_posix_uctx_swap(current_to_save, next_to_load); | |
1434 | ✗ | ret = GATE_RESULT_OK; | |
1435 | } | ||
1436 | ✗ | return ret; | |
1437 | } | ||
1438 | |||
1439 | |||
1440 | typedef struct gate_native_jmp_buf_class | ||
1441 | { | ||
1442 | sigjmp_buf buf; | ||
1443 | } gate_native_jmp_buf_t; | ||
1444 | |||
1445 | 6 | gate_result_t gate_callstack_fork(gate_callstack_jmpbuf_t* jmpbuffer, | |
1446 | gate_entrypoint_t entry, void* param, | ||
1447 | gate_entrypoint_t branch, void* branch_param) | ||
1448 | { | ||
1449 | 6 | gate_result_t volatile ret = GATE_RESULT_OK; | |
1450 | 6 | gate_native_jmp_buf_t* volatile ptr_buf = (gate_native_jmp_buf_t*)jmpbuffer; | |
1451 | |||
1452 | if (sizeof(gate_callstack_jmpbuf_t) < sizeof(gate_native_jmp_buf_t)) | ||
1453 | { | ||
1454 | /* generic jump buffer is to small */ | ||
1455 | return GATE_RESULT_OUTOFMEMORY; | ||
1456 | } | ||
1457 | |||
1458 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2 times.
|
6 | if (0 == sigsetjmp(ptr_buf->buf, 1)) |
1459 | { | ||
1460 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (entry) |
1461 | { | ||
1462 | 6 | ret = entry(param); | |
1463 | } | ||
1464 | } | ||
1465 | else | ||
1466 | { | ||
1467 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (branch) |
1468 | { | ||
1469 | 2 | ret = branch(branch_param); | |
1470 | } | ||
1471 | } | ||
1472 | 6 | gate_mem_clear(jmpbuffer, sizeof(gate_callstack_jmpbuf_t)); | |
1473 | 6 | return ret; | |
1474 | } | ||
1475 | |||
1476 | 2 | void gate_callstack_jump(gate_callstack_jmpbuf_t* jmpbuffer) | |
1477 | { | ||
1478 | 2 | gate_native_jmp_buf_t* ptr_buf = (gate_native_jmp_buf_t*)jmpbuffer; | |
1479 | 2 | siglongjmp(ptr_buf->buf, 1); | |
1480 | } | ||
1481 | |||
1482 | |||
1483 | #endif /* GATE_CALLSTACKS_POSIX_IMPL */ | ||
1484 | |||
1485 | |||
1486 | |||
1487 | #if defined(GATE_CALLSTACKS_EFI_IMPL) | ||
1488 | |||
1489 | #include "gate/platform/efi/efi_gate.h" | ||
1490 | |||
1491 | #if defined(GATE_COMPILER_MSVC) | ||
1492 | # include "gate/platform/windows/win32callstack.h" | ||
1493 | # define gate_callstack_create_impl gate_win32_callstack_create | ||
1494 | # define gate_callstack_switch_impl gate_win32_callstack_switch | ||
1495 | #else | ||
1496 | # include "gate/platform/posix/posixcallstack.h" | ||
1497 | # define gate_callstack_create_impl gate_posix_callstack_create | ||
1498 | # define gate_callstack_switch_impl gate_posix_callstack_switch | ||
1499 | #endif | ||
1500 | |||
1501 | |||
1502 | |||
1503 | gate_result_t gate_callstack_trace(gate_callstack_address_t* addresses, gate_size_t addresses_count, gate_size_t* addresses_used) | ||
1504 | { | ||
1505 | /*TODO*/ | ||
1506 | return GATE_RESULT_NOTIMPLEMENTED; | ||
1507 | } | ||
1508 | gate_result_t gate_callstack_print(gate_callstack_address_t address, char* buffer, gate_size_t buffer_length, gate_size_t* buffer_used) | ||
1509 | { | ||
1510 | /*TODO*/ | ||
1511 | return GATE_RESULT_NOTIMPLEMENTED; | ||
1512 | } | ||
1513 | |||
1514 | |||
1515 | |||
1516 | gate_result_t gate_callstack_create(gate_size_t* ptr_stacksize, void** ptr_callstack) | ||
1517 | { | ||
1518 | gate_result_t ret = GATE_RESULT_FAILED; | ||
1519 | void* ptr; | ||
1520 | gate_size_t stacksize = 0; | ||
1521 | |||
1522 | if (!ptr_stacksize || !ptr_callstack) | ||
1523 | { | ||
1524 | ret = GATE_RESULT_INVALIDARG; | ||
1525 | } | ||
1526 | else | ||
1527 | { | ||
1528 | stacksize = *ptr_stacksize; | ||
1529 | if (stacksize < 4096) | ||
1530 | { | ||
1531 | stacksize = 4096; | ||
1532 | } | ||
1533 | stacksize &= ~((gate_size_t)0xff); | ||
1534 | if (stacksize == 0) | ||
1535 | { | ||
1536 | stacksize = 256 * 1024; | ||
1537 | } | ||
1538 | ptr = gate_mem_alloc(stacksize); | ||
1539 | if (ptr) | ||
1540 | { | ||
1541 | ret = GATE_RESULT_OK; | ||
1542 | if (ptr_callstack) | ||
1543 | { | ||
1544 | *ptr_callstack = ptr; | ||
1545 | *ptr_stacksize = stacksize; | ||
1546 | } | ||
1547 | else | ||
1548 | { | ||
1549 | gate_mem_dealloc(ptr); | ||
1550 | } | ||
1551 | } | ||
1552 | } | ||
1553 | |||
1554 | return ret; | ||
1555 | } | ||
1556 | |||
1557 | gate_result_t gate_callstack_destroy(void* ptr_callstack, gate_size_t stacksize) | ||
1558 | { | ||
1559 | if (!ptr_callstack) | ||
1560 | { | ||
1561 | return GATE_RESULT_INVALIDARG; | ||
1562 | } | ||
1563 | |||
1564 | gate_mem_dealloc(ptr_callstack); | ||
1565 | return GATE_RESULT_OK; | ||
1566 | } | ||
1567 | |||
1568 | |||
1569 | gate_result_t gate_callstack_run(void* ptr_callstack, gate_size_t stacksize, | ||
1570 | gate_callstack_context_t* ptr_caller_ctx_to_save, | ||
1571 | gate_entrypoint_t entry_func, void* param, | ||
1572 | gate_result_t* ptr_returnvalue) | ||
1573 | { | ||
1574 | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | ||
1575 | gate_size_t stack_addr = (gate_size_t)ptr_callstack; | ||
1576 | void* stack_top; | ||
1577 | gate_callstack_context_t context = GATE_INIT_EMPTY; | ||
1578 | void* entry_ret; | ||
1579 | |||
1580 | if (NULL == ptr_caller_ctx_to_save) | ||
1581 | { | ||
1582 | ptr_caller_ctx_to_save = &context; | ||
1583 | } | ||
1584 | |||
1585 | stack_addr += (stacksize - 4); | ||
1586 | stack_addr -= (stack_addr & 0x0f); | ||
1587 | stack_top = (void*)stack_addr; | ||
1588 | |||
1589 | entry_ret = gate_callstack_create_impl(stack_top, ptr_caller_ctx_to_save, entry_func, param); | ||
1590 | ret = GATE_RESULT_OK; | ||
1591 | if (ptr_returnvalue) | ||
1592 | { | ||
1593 | *ptr_returnvalue = (gate_result_t)(gate_intptr_t)entry_ret; | ||
1594 | } | ||
1595 | return ret; | ||
1596 | } | ||
1597 | |||
1598 | gate_result_t gate_callstack_switch(gate_callstack_context_t* current_to_save, | ||
1599 | gate_callstack_context_t* next_to_load) | ||
1600 | { | ||
1601 | gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED; | ||
1602 | if (NULL == gate_callstack_switch_impl(current_to_save, next_to_load)) | ||
1603 | { | ||
1604 | ret = GATE_RESULT_FAILED; | ||
1605 | } | ||
1606 | else | ||
1607 | { | ||
1608 | ret = GATE_RESULT_OK; | ||
1609 | } | ||
1610 | return ret; | ||
1611 | } | ||
1612 | |||
1613 | #endif /* GATE_CALLSTACKS_EFI_IMPL */ | ||
1614 | |||
1615 | |||
1616 | #if defined(GATE_CALLSTACKS_DOS_IMPL) | ||
1617 | |||
1618 | #include "gate/platforms.h" | ||
1619 | #include "gate/platform/dos/doscallstack.h" | ||
1620 | |||
1621 | |||
1622 | gate_result_t gate_callstack_trace(gate_callstack_address_t* addresses, gate_size_t addresses_count, gate_size_t* addresses_used) | ||
1623 | { | ||
1624 | GATE_UNUSED_ARG(addresses); | ||
1625 | GATE_UNUSED_ARG(addresses_count); | ||
1626 | GATE_UNUSED_ARG(addresses_used); | ||
1627 | return GATE_RESULT_FAILED; | ||
1628 | } | ||
1629 | |||
1630 | gate_result_t gate_callstack_print(gate_callstack_address_t address, char* buffer, gate_size_t buffer_length, gate_size_t* buffer_used) | ||
1631 | { | ||
1632 | GATE_UNUSED_ARG(address); | ||
1633 | GATE_UNUSED_ARG(buffer); | ||
1634 | GATE_UNUSED_ARG(buffer_length); | ||
1635 | GATE_UNUSED_ARG(buffer_used); | ||
1636 | return GATE_RESULT_FAILED; | ||
1637 | } | ||
1638 | |||
1639 | #define DEFAULT_STACK_SIZE 16384 | ||
1640 | |||
1641 | gate_result_t gate_callstack_create(gate_size_t* ptr_stacksize, void** ptr_callstack) | ||
1642 | { | ||
1643 | gate_result_t result = GATE_RESULT_OUTOFMEMORY; | ||
1644 | gate_size_t para_count; | ||
1645 | unsigned segment = 0; | ||
1646 | gate_size_t stacksize; | ||
1647 | |||
1648 | if (!ptr_stacksize || !ptr_callstack) | ||
1649 | { | ||
1650 | return GATE_RESULT_INVALIDARG; | ||
1651 | } | ||
1652 | stacksize = *ptr_stacksize; | ||
1653 | |||
1654 | if (stacksize == 0) | ||
1655 | { | ||
1656 | stacksize = DEFAULT_STACK_SIZE; | ||
1657 | } | ||
1658 | if (stacksize > 32768) | ||
1659 | { | ||
1660 | stacksize = 32768; | ||
1661 | } | ||
1662 | if (stacksize < 256) | ||
1663 | { | ||
1664 | stacksize = 256; | ||
1665 | } | ||
1666 | stacksize = (stacksize + 0x0f) & ~((gate_size_t)0x0f); | ||
1667 | |||
1668 | para_count = (stacksize + 15) / 16; | ||
1669 | |||
1670 | result = gate_dos_alloc(para_count, &segment); | ||
1671 | if (GATE_SUCCEEDED(result)) | ||
1672 | { | ||
1673 | *ptr_callstack = (void*)gate_dos_farptr(segment, 0); | ||
1674 | *ptr_stacksize = stacksize; | ||
1675 | } | ||
1676 | return result; | ||
1677 | } | ||
1678 | |||
1679 | gate_result_t gate_callstack_destroy(void* ptr_callstack, gate_size_t stacksize) | ||
1680 | { | ||
1681 | unsigned segment = gate_dos_farptr_seg(ptr_callstack); | ||
1682 | GATE_UNUSED_ARG(stacksize); | ||
1683 | return gate_dos_dealloc(segment); | ||
1684 | } | ||
1685 | |||
1686 | |||
1687 | gate_result_t gate_callstack_run(void* ptr_callstack, gate_size_t stacksize, gate_callstack_context_t* ptr_caller_ctx_to_save, | ||
1688 | gate_entrypoint_t entry_func, void* param, gate_result_t* ptr_returnvalue) | ||
1689 | { | ||
1690 | gate_result_t result; | ||
1691 | char __far* ptr_stack_begin = (char __far*)ptr_callstack; | ||
1692 | char __far* ptr_stack_end; | ||
1693 | |||
1694 | if (stacksize == 0) | ||
1695 | { | ||
1696 | stacksize = DEFAULT_STACK_SIZE; | ||
1697 | } | ||
1698 | gate_mem_clear(ptr_callstack, stacksize); | ||
1699 | ptr_stack_end = ptr_stack_begin + stacksize - 2; | ||
1700 | |||
1701 | |||
1702 | result = gate_dos_callstack_create(ptr_stack_end, ptr_caller_ctx_to_save, entry_func, param); | ||
1703 | if (GATE_SUCCEEDED(result)) | ||
1704 | { | ||
1705 | if (ptr_returnvalue) | ||
1706 | { | ||
1707 | *ptr_returnvalue = result; | ||
1708 | } | ||
1709 | } | ||
1710 | return result; | ||
1711 | } | ||
1712 | |||
1713 | gate_result_t gate_callstack_switch(gate_callstack_context_t* current_to_save, | ||
1714 | gate_callstack_context_t* next_to_load) | ||
1715 | { | ||
1716 | return gate_dos_callstack_switch(current_to_save, next_to_load); | ||
1717 | } | ||
1718 | |||
1719 | #endif /* GATE_CALLSTACKS_DOS_IMPL */ | ||
1720 | |||
1721 | |||
1722 | |||
1723 | #if defined(GATE_CALLSTACKS_NO_IMPL) | ||
1724 | |||
1725 | gate_result_t gate_callstack_trace(gate_callstack_address_t* addresses, gate_size_t addresses_count, gate_size_t* addresses_used) | ||
1726 | { | ||
1727 | (void)addresses; | ||
1728 | (void)addresses_count; | ||
1729 | (void)addresses_used; | ||
1730 | return GATE_RESULT_NOTIMPLEMENTED; | ||
1731 | } | ||
1732 | gate_result_t gate_callstack_print(gate_callstack_address_t address, char* buffer, gate_size_t buffer_length, gate_size_t* buffer_used) | ||
1733 | { | ||
1734 | (void)address; | ||
1735 | (void)buffer; | ||
1736 | (void)buffer_length; | ||
1737 | (void)buffer_used; | ||
1738 | return GATE_RESULT_NOTIMPLEMENTED; | ||
1739 | } | ||
1740 | |||
1741 | gate_result_t gate_callstack_create(gate_size_t* ptr_stacksize, void** ptr_callstack) | ||
1742 | { | ||
1743 | (void)ptr_stacksize; | ||
1744 | (void)ptr_callstack; | ||
1745 | return GATE_RESULT_NOTIMPLEMENTED; | ||
1746 | } | ||
1747 | gate_result_t gate_callstack_destroy(void* ptr_callstack, gate_size_t stacksize) | ||
1748 | { | ||
1749 | (void)ptr_callstack; | ||
1750 | (void)stacksize; | ||
1751 | return GATE_RESULT_NOTIMPLEMENTED; | ||
1752 | } | ||
1753 | gate_result_t gate_callstack_run(void* ptr_callstack, gate_size_t stacksize, gate_callstack_context_t* ptr_caller_ctx_to_save, | ||
1754 | gate_entrypoint_t entry_func, void* param, gate_result_t* ptr_returnvalue) | ||
1755 | { | ||
1756 | (void)ptr_callstack; | ||
1757 | (void)stacksize; | ||
1758 | (void)ptr_caller_ctx_to_save; | ||
1759 | (void)entry_func; | ||
1760 | (void)param; | ||
1761 | (void)ptr_returnvalue; | ||
1762 | return GATE_RESULT_NOTIMPLEMENTED; | ||
1763 | } | ||
1764 | |||
1765 | gate_result_t gate_callstack_switch(gate_callstack_context_t* current_to_save, gate_callstack_context_t* next_to_load) | ||
1766 | { | ||
1767 | (void)current_to_save; | ||
1768 | (void)next_to_load; | ||
1769 | return GATE_RESULT_NOTIMPLEMENTED; | ||
1770 | } | ||
1771 | |||
1772 | |||
1773 | #endif /* GATE_CALLSTACKS_NO_IMPL */ | ||
1774 | |||
1775 |