GCC Code Coverage Report


Directory: src/gate/
File: src/gate/callstacks.c
Date: 2026-02-03 22:06:38
Exec Total Coverage
Lines: 92 116 79.3%
Functions: 11 11 100.0%
Branches: 23 42 54.8%

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
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 # if defined(GATE_COMPILER_CLANG)
479 # define GATE_DEBUG_GETFRAME(frame, ctx) do { \
480 gate_platform.Win32RtlCaptureContext(&ctx); \
481 frame.AddrFrame.Mode = AddrModeFlat; \
482 frame.AddrFrame.Offset = (DWORD64)ctx.Ebp; \
483 frame.AddrStack.Mode = AddrModeFlat; \
484 frame.AddrStack.Offset = (DWORD64)ctx.Esp; \
485 frame.AddrPC.Mode = AddrModeFlat; \
486 frame.AddrPC.Offset = (DWORD64)ctx.Eip; \
487 } while(0)
488 # else
489 # define GATE_DEBUG_GETFRAME(frame, ctx) do { \
490 size_t * ptrFrame = 0; \
491 size_t ptrStack = 0; \
492 _asm { mov ptrFrame, ebp } \
493 _asm { mov ptrStack, esp } \
494 ctx.Ebp = (DWORD)(size_t)(ptrFrame); \
495 ctx.Esp = (DWORD)ptrStack; \
496 ctx.Eip = (DWORD)*(ptrFrame + 1); \
497 frame.AddrFrame.Mode = AddrModeFlat; \
498 frame.AddrFrame.Offset = (DWORD64)ctx.Ebp; \
499 frame.AddrStack.Mode = AddrModeFlat; \
500 frame.AddrStack.Offset = (DWORD64)ctx.Esp; \
501 frame.AddrPC.Mode = AddrModeFlat; \
502 frame.AddrPC.Offset = (DWORD64)ctx.Eip; \
503 } while(0)
504 # endif
505 # else
506 # define GATE_DEBUG_GETFRAME(frame, ctx) do { \
507 frame.AddrFrame.Mode = AddrModeFlat; \
508 frame.AddrFrame.Offset = (DWORD64)0; \
509 frame.AddrStack.Mode = AddrModeFlat; \
510 frame.AddrStack.Offset = (DWORD64)0; \
511 frame.AddrPC.Mode = AddrModeFlat; \
512 frame.AddrPC.Offset = (DWORD64)0; \
513 } while(0)
514 # endif
515 #elif defined(GATE_COMPILER_GCC)
516 # define GATE_WINAPI_CPU_CONTEXT CONTEXT
517 # if defined(GATE_SYS_WIN64)
518 # define MACHINE_FLAG IMAGE_FILE_MACHINE_AMD64
519 # define GATE_DEBUG_GETFRAME(frame, ctx) do { \
520 gate_platform.Win32RtlCaptureContext(&ctx); \
521 frame.AddrFrame.Mode = AddrModeFlat; \
522 frame.AddrFrame.Offset = (DWORD64)ctx.Rbp; \
523 frame.AddrStack.Mode = AddrModeFlat; \
524 frame.AddrStack.Offset = (DWORD64)ctx.Rsp; \
525 frame.AddrPC.Mode = AddrModeFlat; \
526 frame.AddrPC.Offset = (DWORD64)ctx.Rip; \
527 } while(0)
528 # else
529 # define MACHINE_FLAG IMAGE_FILE_MACHINE_I386
530 # define GATE_DEBUG_GETFRAME(frame, ctx) do { \
531 size_t * ptrFrame = 0; \
532 size_t ptrStack = 0; \
533 asm ( "movl %%ebp, %0;" : "=r" ( ptrFrame ) ); \
534 asm ( "movl %%esp, %0;" : "=r" ( ptrStack ) ); \
535 ctx.Ebp = (DWORD)(size_t)(ptrFrame); \
536 ctx.Esp = (DWORD)ptrStack; \
537 ctx.Eip = (DWORD)*(ptrFrame + 1); \
538 frame.AddrFrame.Mode = AddrModeFlat; \
539 frame.AddrFrame.Offset = (DWORD64)ctx.Ebp; \
540 frame.AddrStack.Mode = AddrModeFlat; \
541 frame.AddrStack.Offset = (DWORD64)ctx.Esp; \
542 frame.AddrPC.Mode = AddrModeFlat; \
543 frame.AddrPC.Offset = (DWORD64)ctx.Eip; \
544 } while(0)
545 # endif
546 #elif defined(GATE_COMPILER_WATCOM)
547 # define GATE_WINAPI_CPU_CONTEXT CONTEXT
548 # if (GATE_ARCH == GATE_ARCH_X86IA32)
549 # define MACHINE_FLAG IMAGE_FILE_MACHINE_I386
550 # define GATE_DEBUG_GETFRAME(frame, ctx) do { \
551 size_t * ptrFrame = 0; \
552 size_t ptrStack = 0; \
553 ctx.Ebp = (DWORD)(size_t)(ptrFrame); \
554 ctx.Esp = (DWORD)ptrStack; \
555 ctx.Eip = (DWORD)*(ptrFrame + 1); \
556 frame.AddrFrame.Mode = AddrModeFlat; \
557 frame.AddrFrame.Offset = (DWORD64)ctx.Ebp; \
558 frame.AddrStack.Mode = AddrModeFlat; \
559 frame.AddrStack.Offset = (DWORD64)ctx.Esp; \
560 frame.AddrPC.Mode = AddrModeFlat; \
561 frame.AddrPC.Offset = (DWORD64)ctx.Eip; \
562 } while(0)
563 # endif
564 #elif defined(GATE_COMPILER_TCC)
565 typedef struct
566 {
567 DWORD ControlWord;
568 DWORD StatusWord;
569 DWORD TagWord;
570 DWORD ErrorOffset;
571 DWORD ErrorSelector;
572 DWORD DataOffset;
573 DWORD DataSelector;
574 BYTE RegisterArea[80];
575 DWORD Spare0;
576 } WIN32_CPU_FLOATING_SAVE_AREA;
577
578 typedef struct
579 {
580 DWORD ContextFlags;
581
582 DWORD Dr0;
583 DWORD Dr1;
584 DWORD Dr2;
585 DWORD Dr3;
586 DWORD Dr6;
587 DWORD Dr7;
588
589 WIN32_CPU_FLOATING_SAVE_AREA FloatSave;
590
591 DWORD SegGs;
592 DWORD SegFs;
593 DWORD SegEs;
594 DWORD SegDs;
595
596 DWORD Edi;
597 DWORD Esi;
598 DWORD Ebx;
599 DWORD Edx;
600 DWORD Ecx;
601 DWORD Eax;
602
603 DWORD Ebp;
604 DWORD Eip;
605 DWORD SegCs;
606 DWORD EFlags;
607 DWORD Esp;
608 DWORD SegSs;
609
610 BYTE ExtendedRegisters[512];
611 } WIN32_CPU_CONTEXT;
612
613 #define GATE_WINAPI_CPU_CONTEXT WIN32_CPU_CONTEXT
614 # if (GATE_ARCH == GATE_ARCH_X86IA32)
615 # define MACHINE_FLAG IMAGE_FILE_MACHINE_I386
616 # define GATE_DEBUG_GETFRAME(frame, ctx) do { \
617 size_t * ptrFrame = 0; \
618 size_t ptrStack = 0; \
619 ctx.Ebp = (DWORD)(size_t)(ptrFrame); \
620 ctx.Esp = (DWORD)ptrStack; \
621 ctx.Eip = (DWORD)*(ptrFrame + 1); \
622 frame.AddrFrame.Mode = AddrModeFlat; \
623 frame.AddrFrame.Offset = (DWORD64)ctx.Ebp; \
624 frame.AddrStack.Mode = AddrModeFlat; \
625 frame.AddrStack.Offset = (DWORD64)ctx.Esp; \
626 frame.AddrPC.Mode = AddrModeFlat; \
627 frame.AddrPC.Offset = (DWORD64)ctx.Eip; \
628 } while(0)
629 # endif
630
631 #endif
632
633
634 gate_result_t gate_callstack_trace(gate_callstack_address_t* addresses, gate_size_t addresses_count, gate_size_t* addresses_used)
635 {
636 gate_result_t ret;
637 HANDLE hThread = GetCurrentThread();
638 HANDLE hProcess = NULL;
639 STACKFRAME64 frame;
640 GATE_WINAPI_CPU_CONTEXT ctx;
641
642 DWORD dwMachineFlag = MACHINE_FLAG;
643 LPCONTEXT pctx = NULL;
644 gate_size_t frames_found = 0;
645 BOOL symcleanup_required = FALSE;
646
647 do
648 {
649 if (!gate_callstack_init())
650 {
651 ret = GATE_RESULT_NOTSUPPORTED;
652 break;
653 }
654
655 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId());
656 if (hProcess == NULL)
657 {
658 ret = GATE_RESULT_OUTOFRESOURCES;
659 break;
660 }
661
662 symcleanup_required = SymInitialize(hProcess, NULL, TRUE);
663
664 gate_mem_clear(&frame, sizeof(frame));
665 gate_mem_clear(&ctx, sizeof(ctx));
666
667 GATE_DEBUG_GETFRAME(frame, ctx);
668
669 #if (GATE_ARCH == GATE_ARCH_ARM64)
670 dwMachineFlag = IMAGE_FILE_MACHINE_ARM64;
671 pctx = &ctx;
672 #elif (GATE_ARCH == GATE_ARCH_X86X64)
673 dwMachineFlag = IMAGE_FILE_MACHINE_AMD64;
674 pctx = &ctx;
675 #endif
676 if (!StackWalk64(dwMachineFlag, hProcess, hThread, &frame, pctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
677 {
678 ret = GATE_RESULT_FAILED;
679 break;
680 }
681 ret = GATE_RESULT_OK;
682 while (addresses_count-- != 0)
683 {
684 if (StackWalk64(dwMachineFlag, hProcess, hThread, &frame, pctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
685 {
686 *addresses = (gate_callstack_address_t)(gate_uintptr_t)frame.AddrPC.Offset;
687 ++frames_found;
688 ++addresses;
689 }
690 else
691 {
692 break;
693 }
694 }
695 if (addresses_used != 0)
696 {
697 *addresses_used = frames_found;
698 }
699 } while (0);
700
701 if (symcleanup_required)
702 {
703 SymCleanup(hProcess);
704 }
705
706 if (hProcess != NULL)
707 {
708 CloseHandle(hProcess);
709 }
710
711 return ret;
712 }
713 gate_result_t gate_callstack_print(gate_callstack_address_t address, char* buffer, gate_size_t buffer_length, gate_size_t* buffer_used)
714 {
715 gate_result_t ret = GATE_RESULT_FAILED;
716 HANDLE hProcess = NULL;
717 IMAGEHLP_MODULE64 mod64;
718 DWORD64 dwAddr;
719 DWORD64 dwDisp = 0;
720 char bufSym[sizeof(IMAGEHLP_SYMBOL64) + MAX_SYM_NAME];
721 IMAGEHLP_SYMBOL64* pSym = (IMAGEHLP_SYMBOL64*)&bufSym[0];
722 gate_size_t len;
723
724 do
725 {
726 if (!gate_callstack_init())
727 {
728 ret = GATE_RESULT_NOTSUPPORTED;
729 break;
730 }
731
732 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId());
733 if (hProcess == NULL)
734 {
735 ret = GATE_RESULT_OUTOFRESOURCES;
736 break;
737 }
738
739 gate_mem_clear(&mod64, sizeof(mod64));
740 mod64.SizeOfStruct = sizeof(mod64);
741 dwAddr = (DWORD64)(gate_uintptr_t)address;
742 SymGetModuleInfo64(hProcess, dwAddr, &mod64);
743 gate_mem_clear(pSym, sizeof(IMAGEHLP_SYMBOL64) + MAX_SYM_NAME);
744 pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
745 pSym->MaxNameLength = MAX_SYM_NAME;
746
747 if (SymGetSymFromAddr64(hProcess, dwAddr, &dwDisp, pSym))
748 {
749 len = gate_str_print_text(buffer, buffer_length, pSym->Name, gate_str_length(pSym->Name));
750 if (buffer_used != NULL)
751 {
752 *buffer_used = len;
753 }
754 ret = GATE_RESULT_OK;
755 }
756 else
757 {
758 gate_str_print_hex_uint64(buffer, buffer_length, (gate_uint64_t)(gate_uintptr_t)address, false);
759 ret = GATE_RESULT_OK_PARTIAL;
760 }
761 } while (0);
762
763 if (hProcess != NULL)
764 {
765 CloseHandle(hProcess);
766 }
767
768 return ret;
769 }
770
771 #endif /* GATE_CALLSTACKS_WIN32_DBG_IMPL */
772
773
774 #ifdef GATE_CALLSTACKS_WIN32_CALLSTACK_IMPL
775
776 #include "gate/platform/windows/win32callstack.h"
777
778 #include "gate/platforms.h"
779 #include <windows.h>
780
781
782 #if defined(GATE_COMPILE_ASM_SUPPORT)
783
784 #ifndef MEM_COMMIT
785 #define MEM_COMMIT 0x1000
786 #endif
787
788 #ifndef PAGE_READWRITE
789 #define PAGE_READWRITE 0x04
790 #endif
791
792 #ifndef PAGE_EXECUTE_READ
793 #define PAGE_EXECUTE_READ 0x20
794 #endif
795
796 #ifndef PAGE_EXECUTE_READWRITE
797 #define PAGE_EXECUTE_READWRITE 0x40
798 #endif
799
800 #ifndef MEM_RELEASE
801 #define MEM_RELEASE 0x8000
802 #endif
803
804 gate_result_t gate_callstack_create(gate_size_t* ptr_stacksize, void** ptr_callstack)
805 {
806 gate_result_t ret = GATE_RESULT_FAILED;
807 LPVOID stack_buffer = NULL;
808 DWORD old_protect = 0;
809 gate_size_t stacksize;
810 do
811 {
812 if (!ptr_callstack || !ptr_stacksize)
813 {
814 ret = GATE_RESULT_INVALIDARG;
815 break;
816 }
817 stacksize = *ptr_stacksize;
818 stacksize &= ~((gate_size_t)0xff);
819 if (stacksize == 0)
820 {
821 stacksize = 256 * 1024;
822 }
823 if (stacksize < 4096)
824 {
825 stacksize = 4096;
826 }
827 stack_buffer = VirtualAlloc(NULL, stacksize, MEM_COMMIT, PAGE_READWRITE);
828 if (NULL == stack_buffer)
829 {
830 break;
831 }
832 if (!VirtualProtect(stack_buffer, stacksize, PAGE_EXECUTE_READWRITE, &old_protect))
833 {
834 VirtualFree(stack_buffer, 0, MEM_RELEASE);
835 }
836
837 ret = GATE_RESULT_OK;
838 *ptr_stacksize = stacksize;
839 *ptr_callstack = stack_buffer;
840
841 } while (0);
842 return ret;
843 }
844 gate_result_t gate_callstack_destroy(void* ptr_callstack, gate_size_t stacksize)
845 {
846 gate_result_t ret = GATE_RESULT_FAILED;
847 if (ptr_callstack)
848 {
849 if (VirtualFree((LPVOID)ptr_callstack, 0, MEM_RELEASE))
850 {
851 ret = GATE_RESULT_OK;
852 }
853 }
854 return ret;
855 }
856
857
858 gate_result_t gate_callstack_run(void* ptr_callstack, gate_size_t stacksize,
859 gate_callstack_context_t* ptr_caller_ctx_to_save,
860 gate_entrypoint_t entry_func, void* param,
861 gate_result_t* ptr_returnvalue)
862 {
863 gate_result_t ret = GATE_RESULT_FAILED;
864 gate_size_t stack_addr = (gate_size_t)ptr_callstack;
865 gate_callstack_context_t dummy_context = GATE_INIT_EMPTY;
866 void* entry_ret = NULL;
867
868 #if !defined(GATE_SYS_WINCE)
869 gate_size_t stack_top = stack_addr + (stacksize - 4);
870 stack_top -= (stack_top & 0x0f);
871 entry_ret = gate_win32_callstack_create((void*)stack_top,
872 (ptr_caller_ctx_to_save != NULL) ? ptr_caller_ctx_to_save : &dummy_context,
873 entry_func, param);
874 ret = GATE_RESULT_OK;
875 #endif
876 if (ptr_returnvalue)
877 {
878 *ptr_returnvalue = (gate_result_t)(gate_intptr_t)entry_ret;
879 }
880 return ret;
881 }
882
883 gate_result_t gate_callstack_switch(gate_callstack_context_t* current_to_save,
884 gate_callstack_context_t* next_to_load)
885 {
886 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
887 #if !defined(GATE_SYS_WINCE)
888 if (NULL == gate_win32_callstack_switch(current_to_save, next_to_load))
889 {
890 ret = GATE_RESULT_FAILED;
891 }
892 else
893 {
894 ret = GATE_RESULT_OK;
895 }
896 #endif
897 return ret;
898 }
899
900 #else /* GATE_COMPILE_ASM_SUPPORT */
901
902 /* use FIBERs if no native ASM support is present */
903
904 typedef struct gate_callstack_fiber_class
905 {
906 LPVOID fiber;
907 LPVOID parent;
908 gate_entrypoint_t entrypoint;
909 void* param;
910 gate_result_t result;
911
912 } gate_callstack_fiber_t;
913
914
915 static VOID WINAPI gate_callstack_fiber_dispatcher(LPVOID lpFiberParameter)
916 {
917 gate_callstack_fiber_t* ptr_fiber = (gate_callstack_fiber_t*)lpFiberParameter;
918 if (ptr_fiber && ptr_fiber->entrypoint)
919 {
920 ptr_fiber->result = ptr_fiber->entrypoint(ptr_fiber->param);
921 gate_win32_fibers()->Win32SwitchToFiber(ptr_fiber->parent);
922 }
923 }
924
925
926 gate_result_t gate_callstack_create(gate_size_t* ptr_stacksize, void** ptr_callstack)
927 {
928 gate_result_t ret = GATE_RESULT_FAILED;
929 gate_callstack_fiber_t* ptr_fiber = NULL;
930 gate_size_t stacksize = 0;
931 gate_win32_fibers_t* fibers = NULL;
932
933 do
934 {
935 if (!ptr_callstack || !ptr_stacksize)
936 {
937 ret = GATE_RESULT_INVALIDARG;
938 break;
939 }
940 stacksize = *ptr_stacksize;
941 stacksize &= ~((gate_size_t)0xff);
942 if (stacksize == 0)
943 {
944 stacksize = 256 * 1024;
945 }
946 if (stacksize < 4096)
947 {
948 stacksize = 4096;
949 }
950
951 fibers = gate_win32_fibers();
952
953 if (!fibers)
954 {
955 ret = GATE_RESULT_NOTSUPPORTED;
956 break;
957 }
958
959 ptr_fiber = (gate_callstack_fiber_t*)gate_mem_alloc(sizeof(gate_callstack_fiber_t));
960 if (!ptr_fiber)
961 {
962 ret = GATE_RESULT_OUTOFMEMORY;
963 break;
964 }
965 gate_mem_clear(ptr_fiber, sizeof(gate_callstack_fiber_t));
966
967 ptr_fiber->fiber = fibers->Win32CreateFiber(stacksize, &gate_callstack_fiber_dispatcher, ptr_fiber);
968 if (ptr_fiber == NULL)
969 {
970 ret = gate_platform_print_last_error(NULL, 0);
971 break;
972 }
973
974 *ptr_callstack = (void*)ptr_fiber;
975 *ptr_stacksize = stacksize;
976 ptr_fiber = NULL;
977 ret = GATE_RESULT_OK;
978 } while (0);
979
980 if (ptr_fiber)
981 {
982 gate_mem_dealloc(ptr_fiber);
983 }
984 return ret;
985 }
986 gate_result_t gate_callstack_destroy(void* ptr_callstack, gate_size_t stacksize)
987 {
988 gate_result_t ret = GATE_RESULT_FAILED;
989 gate_callstack_fiber_t* ptr_fiber = (gate_callstack_fiber_t*)ptr_callstack;
990
991 GATE_UNUSED_ARG(stacksize);
992
993 if (ptr_fiber)
994 {
995 gate_win32_fibers_t* fibers = gate_win32_fibers();
996 if (fibers)
997 {
998 fibers->Win32DeleteFiber(ptr_fiber->fiber);
999 }
1000 gate_mem_dealloc(ptr_fiber);
1001 ret = GATE_RESULT_OK;
1002 }
1003 return ret;
1004 }
1005
1006
1007 gate_result_t gate_callstack_run(void* ptr_callstack, gate_size_t stacksize,
1008 gate_callstack_context_t* ptr_caller_ctx_to_save,
1009 gate_entrypoint_t entry_func, void* param,
1010 gate_result_t* ptr_returnvalue)
1011 {
1012 gate_result_t ret = GATE_RESULT_FAILED;
1013 gate_callstack_fiber_t* ptr_fiber = (gate_callstack_fiber_t*)ptr_callstack;
1014 gate_callstack_context_t local_context = GATE_INIT_EMPTY;
1015 LPVOID current_fiber = NULL;
1016 gate_bool_t was_fiber = false;
1017
1018 GATE_UNUSED_ARG(stacksize);
1019
1020 do
1021 {
1022 gate_win32_fibers_t* fibers = gate_win32_fibers();
1023 if (!fibers)
1024 {
1025 break;
1026 }
1027
1028 if (NULL == ptr_caller_ctx_to_save)
1029 {
1030 ptr_caller_ctx_to_save = &local_context;
1031 }
1032
1033 ptr_fiber->entrypoint = entry_func;
1034 ptr_fiber->param = param;
1035
1036 current_fiber = fibers->Win32ConvertThreadToFiber(NULL);
1037 if (current_fiber != NULL)
1038 {
1039 /* previously a thread, now a fiber */
1040 was_fiber = false;
1041 }
1042 else
1043 {
1044 /* was already a fiber, retrieve its handle*/
1045 was_fiber = true;
1046 current_fiber = fibers->Win32GetCurrentFiber();
1047 if (NULL == current_fiber)
1048 {
1049 ret = GATE_RESULT_OUTOFRESOURCES;
1050 break;
1051 }
1052 }
1053 ptr_fiber->parent = current_fiber;
1054 ptr_caller_ctx_to_save->store[0] = current_fiber;
1055
1056 fibers->Win32SwitchToFiber(ptr_fiber->fiber);
1057
1058 ptr_fiber->parent = NULL;
1059
1060 if (ptr_returnvalue)
1061 {
1062 *ptr_returnvalue = ptr_fiber->result;
1063 }
1064
1065 if (!was_fiber)
1066 {
1067 if (fibers->Win32ConvertFiberToThread)
1068 {
1069 fibers->Win32ConvertFiberToThread();
1070 }
1071 }
1072 ret = GATE_RESULT_OK;
1073 } while (0);
1074
1075 return ret;
1076 }
1077
1078 gate_result_t gate_callstack_switch(gate_callstack_context_t* current_to_save,
1079 gate_callstack_context_t* next_to_load)
1080 {
1081 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1082 #if !defined(GATE_SYS_WINCE)
1083 gate_win32_fibers_t* fibers = gate_win32_fibers();
1084 if (fibers->Win32SwitchToFiber)
1085 {
1086 PVOID current_fiber = fibers->Win32GetCurrentFiber();
1087 PVOID next_fiber = next_to_load->store[0];
1088 current_to_save->store[0] = current_fiber;
1089 fibers->Win32SwitchToFiber(next_fiber);
1090 ret = GATE_RESULT_OK;
1091 }
1092 #endif
1093 return ret;
1094 }
1095
1096
1097 #endif /* GATE_COMPILE_ASM_SUPPORT */
1098
1099
1100 #endif /* GATE_CALLSTACKS_WIN32_CALLSTACK_IMPL */
1101
1102
1103
1104
1105
1106
1107 #if defined(GATE_CALLSTACKS_POSIX_IMPL)
1108
1109 #include <stdlib.h>
1110 #include <dlfcn.h>
1111 #include <stdio.h>
1112 #include <setjmp.h>
1113 #include <signal.h>
1114 #include <sys/mman.h>
1115 #include "gate/platform/posix/posixcallstack.h"
1116 #include "gate/platform/posix/posixucontext.h"
1117 #include "gate/debugging.h"
1118
1119 #if defined(HAVE_BACKTRACE)
1120 #include <execinfo.h>
1121 #endif
1122
1123 #define DEFAULT_STACK_SIZE (1024 * 1024)
1124 #define MINMUM_STACK_SIZE (4 * 1024)
1125
1126 #if defined(GATE_SYS_FREEBSD)
1127 typedef size_t backtrace_length_t;
1128 #else
1129 typedef int backtrace_length_t;
1130 #endif
1131
1132 typedef backtrace_length_t(*backtrace_func_t)(void** buffer, backtrace_length_t size);
1133 typedef char** (*backtrace_symbols_func_t)(void* const* buffer, backtrace_length_t size);
1134
1135 static backtrace_func_t volatile backtrace_func = NULL;
1136 static backtrace_symbols_func_t volatile backtrace_symbols_func = NULL;
1137
1138
1139 #if defined(HAVE_BACKTRACE)
1140
1141 2 static gate_bool_t load_backtrace_functions()
1142 {
1143 2 backtrace_func = &backtrace;
1144 2 backtrace_symbols_func = &backtrace_symbols;
1145 2 return true;
1146 }
1147
1148 #else
1149
1150 static void* volatile execinfo_symbols = NULL;
1151
1152 static void close_execinfo_atexit()
1153 {
1154 if (NULL != execinfo_symbols)
1155 {
1156 void* const lib = execinfo_symbols;
1157 execinfo_symbols = NULL;
1158 dlclose(lib);
1159 }
1160 }
1161
1162 static void load_backtrace_from_libexecinfo()
1163 {
1164 if (execinfo_symbols == NULL)
1165 {
1166 execinfo_symbols = gate_posix_dlopen("libexecinfo.so", RTLD_GLOBAL | RTLD_NOW);
1167 if (NULL != execinfo_symbols)
1168 {
1169 gate_platform_atexit(&close_execinfo_atexit);
1170 }
1171 }
1172
1173 if (execinfo_symbols != NULL)
1174 {
1175 backtrace_func = dlsym(execinfo_symbols, "backtrace");
1176 backtrace_symbols_func = dlsym(execinfo_symbols, "backtrace_symbols");
1177 }
1178 }
1179
1180 static gate_bool_t load_backtrace_functions()
1181 {
1182 if (!backtrace_func || backtrace_symbols_func)
1183 {
1184 /* lookup in global function table: */
1185 backtrace_func = gate_posix_global_sym("backtrace");
1186 backtrace_symbols_func = gate_posix_global_sym("backtrace_symbols");
1187
1188 if ((NULL == backtrace_func) || (NULL == backtrace_symbols_func))
1189 {
1190 load_backtrace_from_libexecinfo();
1191 }
1192 }
1193 return backtrace_func && backtrace_symbols_func;
1194 }
1195
1196 #endif
1197
1198
1199 1 gate_result_t gate_callstack_trace(gate_callstack_address_t* addresses, gate_size_t addresses_count, gate_size_t* addresses_used)
1200 {
1201 1 gate_result_t ret = GATE_RESULT_OK;
1202 void* stackaddress[1024];
1203 backtrace_length_t index;
1204 backtrace_length_t stackaddress_count;
1205
1206 1 load_backtrace_functions();
1207
1208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!backtrace_func)
1209 {
1210 GATE_DEBUG_TRACE("backtrace() not supported");
1211 return GATE_RESULT_NOTSUPPORTED;
1212 }
1213
1214 1 stackaddress_count = backtrace_func(stackaddress, sizeof(stackaddress) / sizeof(stackaddress[0]));
1215
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stackaddress_count > 0)
1216 {
1217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stackaddress_count > (backtrace_length_t)addresses_count)
1218 {
1219 stackaddress_count = (backtrace_length_t)addresses_count;
1220 }
1221
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 times.
13 for (index = 0; index != stackaddress_count; ++index)
1222 {
1223 12 addresses[index] = stackaddress[index];
1224 }
1225 1 *addresses_used = (gate_size_t)stackaddress_count;
1226 1 ret = GATE_RESULT_OK;
1227 }
1228 else
1229 {
1230 *addresses_used = 0;
1231 }
1232 1 return ret;
1233 }
1234
1235 1 gate_result_t gate_callstack_print(gate_callstack_address_t address, char* buffer, gate_size_t buffer_length, gate_size_t* buffer_used)
1236 {
1237 gate_size_t len;
1238 char** names;
1239
1240 1 load_backtrace_functions();
1241
1242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (backtrace_symbols_func == NULL)
1243 {
1244 return GATE_RESULT_NOTSUPPORTED;
1245 }
1246
1247 1 names = backtrace_symbols_func((void**)&address, 1);
1248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (names == NULL)
1249 {
1250 return GATE_RESULT_FAILED;
1251 }
1252
1253 1 len = gate_str_print_text(buffer, buffer_length, names[0], gate_str_length(names[0]));
1254 1 free(names);
1255 1 buffer[len] = 0;
1256 1 *buffer_used = len;
1257 1 return GATE_RESULT_OK;
1258 }
1259
1260 #define GATE_CALLSTACK_MALLOC 1
1261
1262 6 static void check_stack_size(gate_size_t* ptr_stacksize)
1263 {
1264
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (*ptr_stacksize == 0)
1265 {
1266 1 *ptr_stacksize = DEFAULT_STACK_SIZE;
1267 }
1268
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (*ptr_stacksize < MINMUM_STACK_SIZE)
1269 {
1270 *ptr_stacksize = MINMUM_STACK_SIZE;
1271 }
1272 /* apply 32-bit maximum and 16-bit alignment */
1273 6 *ptr_stacksize &= 0xfffffff0;
1274 6 }
1275
1276 2 gate_result_t gate_callstack_create(gate_size_t* ptr_stacksize, void** ptr_callstack)
1277 {
1278 void* ptr;
1279 gate_size_t stacksize;
1280
1281 2 check_stack_size(ptr_stacksize);
1282 2 stacksize = *ptr_stacksize;
1283
1284 #if defined(GATE_CALLSTACK_MALLOC)
1285 2 ptr = gate_mem_alloc(stacksize);
1286 #else
1287 ptr = mmap(NULL, stacksize, PROT_READ | PROT_WRITE /*| PROT_EXEC*/,
1288 MAP_PRIVATE | MAP_ANONYMOUS /*| MAP_GROWSDOWN*/ | MAP_STACK, -1, 0);
1289 if (ptr == MAP_FAILED)
1290 {
1291 return GATE_RESULT_FAILED;
1292 }
1293 #endif
1294
1295
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (ptr_callstack)
1296 {
1297 2 *ptr_callstack = ptr;
1298 }
1299 else
1300 {
1301 gate_callstack_destroy(ptr, stacksize);
1302 }
1303 2 return GATE_RESULT_OK;
1304 }
1305
1306 2 gate_result_t gate_callstack_destroy(void* ptr_callstack, gate_size_t stacksize)
1307 {
1308 2 check_stack_size(&stacksize);
1309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!ptr_callstack)
1310 {
1311 return GATE_RESULT_INVALIDARG;
1312 }
1313 #if defined(GATE_CALLSTACK_MALLOC)
1314 2 gate_mem_dealloc(ptr_callstack);
1315 #else
1316 if (0 == munmap(ptr_callstack, stacksize))
1317 {
1318 return GATE_RESULT_OK;
1319 }
1320 else
1321 {
1322 return GATE_RESULT_FAILED;
1323 }
1324 #endif
1325 2 return GATE_RESULT_OK;
1326 }
1327
1328 typedef struct gate_callstack_session_class
1329 {
1330 gate_entrypoint_t entry_func;
1331 void* param;
1332 gate_result_t* ptr_returnvalue;
1333 gate_callstack_context_t* parent_context;
1334 } gate_callstack_session_t;
1335
1336 union gate_callstack_entry_dispatcher_args
1337 {
1338 gate_callstack_session_t* session;
1339 int args[4];
1340 };
1341
1342 2 static void gate_callstack_entry_dispatcher(int a0, int a1, int a2, int a3)
1343 {
1344 union gate_callstack_entry_dispatcher_args args;
1345 gate_result_t result;
1346 gate_callstack_context_t dummy_context;
1347
1348 2 args.args[0] = a0;
1349 2 args.args[1] = a1;
1350 2 args.args[2] = a2;
1351 2 args.args[3] = a3;
1352 2 result = args.session->entry_func(args.session->param);
1353
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (args.session->ptr_returnvalue)
1354 {
1355 1 *args.session->ptr_returnvalue = result;
1356 }
1357 1 gate_posix_uctx_set(args.session->parent_context);
1358 }
1359
1360 2 gate_result_t gate_callstack_run(void* ptr_callstack, gate_size_t stacksize,
1361 gate_callstack_context_t* ptr_caller_ctx_to_save,
1362 gate_entrypoint_t entry_func, void* param,
1363 gate_result_t* ptr_returnvalue)
1364 {
1365 2 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1366 2 gate_size_t stack_addr = (gate_size_t)ptr_callstack;
1367 void* stack_top;
1368 2 gate_callstack_context_t context = GATE_INIT_EMPTY;
1369 2 gate_callstack_context_t new_stack_context = GATE_INIT_EMPTY;
1370 void* entry_ret;
1371 gate_callstack_session_t session;
1372 union gate_callstack_entry_dispatcher_args disp_args;
1373
1374 2 check_stack_size(&stacksize);
1375
1376
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (NULL == ptr_caller_ctx_to_save)
1377 {
1378 1 ptr_caller_ctx_to_save = &context;
1379 }
1380
1381
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (gate_posix_callstack_supported())
1382 {
1383 stack_addr += (stacksize - 4);
1384 stack_addr -= (stack_addr & 0x0f);
1385 stack_top = (void*)stack_addr;
1386
1387 entry_ret = gate_posix_callstack_create(stack_top, ptr_caller_ctx_to_save, entry_func, param);
1388 ret = GATE_RESULT_OK;
1389 if (ptr_returnvalue)
1390 {
1391 *ptr_returnvalue = (gate_result_t)(gate_intptr_t)entry_ret;
1392 }
1393 }
1394 else
1395 {
1396 do
1397 {
1398 2 ret = gate_posix_uctx_init();
1399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
1400
1401
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (0 != gate_posix_uctx_get(&new_stack_context))
1402 {
1403 ret = GATE_RESULT_FAILED;
1404 break;
1405 }
1406 2 gate_posix_uctx_setup(&new_stack_context, ptr_callstack, stacksize);
1407 2 session.entry_func = entry_func;
1408 2 session.param = param;
1409 2 session.ptr_returnvalue = ptr_returnvalue;
1410 2 session.parent_context = ptr_caller_ctx_to_save;
1411 2 disp_args.session = &session;
1412 2 gate_posix_uctx_make(&new_stack_context, &gate_callstack_entry_dispatcher,
1413 disp_args.args[0], disp_args.args[1], disp_args.args[2], disp_args.args[3]);
1414 2 gate_posix_uctx_swap(ptr_caller_ctx_to_save, &new_stack_context);
1415
1416 2 ret = GATE_RESULT_OK;
1417 } while (0);
1418 }
1419 2 return ret;
1420 }
1421
1422 1 gate_result_t gate_callstack_switch(gate_callstack_context_t* current_to_save, gate_callstack_context_t* next_to_load)
1423 {
1424 1 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1425
1426
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (gate_posix_callstack_supported())
1427 {
1428 if (NULL == gate_posix_callstack_switch(current_to_save, next_to_load))
1429 {
1430 ret = GATE_RESULT_FAILED;
1431 }
1432 else
1433 {
1434 ret = GATE_RESULT_OK;
1435 }
1436 }
1437 else
1438 {
1439 1 gate_posix_uctx_swap(current_to_save, next_to_load);
1440 ret = GATE_RESULT_OK;
1441 }
1442 return ret;
1443 }
1444
1445
1446 typedef struct gate_native_jmp_buf_class
1447 {
1448 sigjmp_buf buf;
1449 } gate_native_jmp_buf_t;
1450
1451 6 gate_result_t gate_callstack_fork(gate_callstack_jmpbuf_t* jmpbuffer,
1452 gate_entrypoint_t entry, void* param,
1453 gate_entrypoint_t branch, void* branch_param)
1454 {
1455 6 gate_result_t volatile ret = GATE_RESULT_OK;
1456 6 gate_native_jmp_buf_t* volatile ptr_buf = (gate_native_jmp_buf_t*)jmpbuffer;
1457
1458 if (sizeof(gate_callstack_jmpbuf_t) < sizeof(gate_native_jmp_buf_t))
1459 {
1460 /* generic jump buffer is to small */
1461 return GATE_RESULT_OUTOFMEMORY;
1462 }
1463
1464
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2 times.
6 if (0 == sigsetjmp(ptr_buf->buf, 1))
1465 {
1466
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (entry)
1467 {
1468 6 ret = entry(param);
1469 }
1470 }
1471 else
1472 {
1473
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (branch)
1474 {
1475 2 ret = branch(branch_param);
1476 }
1477 }
1478 6 gate_mem_clear(jmpbuffer, sizeof(gate_callstack_jmpbuf_t));
1479 6 return ret;
1480 }
1481
1482 2 void gate_callstack_jump(gate_callstack_jmpbuf_t* jmpbuffer)
1483 {
1484 2 gate_native_jmp_buf_t* ptr_buf = (gate_native_jmp_buf_t*)jmpbuffer;
1485 2 siglongjmp(ptr_buf->buf, 1);
1486 }
1487
1488
1489 #endif /* GATE_CALLSTACKS_POSIX_IMPL */
1490
1491
1492
1493 #if defined(GATE_CALLSTACKS_EFI_IMPL)
1494
1495 #include "gate/platform/efi/efi_gate.h"
1496
1497 #if defined(GATE_COMPILER_MSVC)
1498 # include "gate/platform/windows/win32callstack.h"
1499 # define gate_callstack_create_impl gate_win32_callstack_create
1500 # define gate_callstack_switch_impl gate_win32_callstack_switch
1501 #else
1502 # include "gate/platform/posix/posixcallstack.h"
1503 # define gate_callstack_create_impl gate_posix_callstack_create
1504 # define gate_callstack_switch_impl gate_posix_callstack_switch
1505 #endif
1506
1507
1508
1509 gate_result_t gate_callstack_trace(gate_callstack_address_t* addresses, gate_size_t addresses_count, gate_size_t* addresses_used)
1510 {
1511 /*TODO*/
1512 return GATE_RESULT_NOTIMPLEMENTED;
1513 }
1514 gate_result_t gate_callstack_print(gate_callstack_address_t address, char* buffer, gate_size_t buffer_length, gate_size_t* buffer_used)
1515 {
1516 /*TODO*/
1517 return GATE_RESULT_NOTIMPLEMENTED;
1518 }
1519
1520
1521
1522 gate_result_t gate_callstack_create(gate_size_t* ptr_stacksize, void** ptr_callstack)
1523 {
1524 gate_result_t ret = GATE_RESULT_FAILED;
1525 void* ptr;
1526 gate_size_t stacksize = 0;
1527
1528 if (!ptr_stacksize || !ptr_callstack)
1529 {
1530 ret = GATE_RESULT_INVALIDARG;
1531 }
1532 else
1533 {
1534 stacksize = *ptr_stacksize;
1535 if (stacksize < 4096)
1536 {
1537 stacksize = 4096;
1538 }
1539 stacksize &= ~((gate_size_t)0xff);
1540 if (stacksize == 0)
1541 {
1542 stacksize = 256 * 1024;
1543 }
1544 ptr = gate_mem_alloc(stacksize);
1545 if (ptr)
1546 {
1547 ret = GATE_RESULT_OK;
1548 if (ptr_callstack)
1549 {
1550 *ptr_callstack = ptr;
1551 *ptr_stacksize = stacksize;
1552 }
1553 else
1554 {
1555 gate_mem_dealloc(ptr);
1556 }
1557 }
1558 }
1559
1560 return ret;
1561 }
1562
1563 gate_result_t gate_callstack_destroy(void* ptr_callstack, gate_size_t stacksize)
1564 {
1565 if (!ptr_callstack)
1566 {
1567 return GATE_RESULT_INVALIDARG;
1568 }
1569
1570 gate_mem_dealloc(ptr_callstack);
1571 return GATE_RESULT_OK;
1572 }
1573
1574
1575 gate_result_t gate_callstack_run(void* ptr_callstack, gate_size_t stacksize,
1576 gate_callstack_context_t* ptr_caller_ctx_to_save,
1577 gate_entrypoint_t entry_func, void* param,
1578 gate_result_t* ptr_returnvalue)
1579 {
1580 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1581 gate_size_t stack_addr = (gate_size_t)ptr_callstack;
1582 void* stack_top;
1583 gate_callstack_context_t context = GATE_INIT_EMPTY;
1584 void* entry_ret;
1585
1586 if (NULL == ptr_caller_ctx_to_save)
1587 {
1588 ptr_caller_ctx_to_save = &context;
1589 }
1590
1591 stack_addr += (stacksize - 4);
1592 stack_addr -= (stack_addr & 0x0f);
1593 stack_top = (void*)stack_addr;
1594
1595 entry_ret = gate_callstack_create_impl(stack_top, ptr_caller_ctx_to_save, entry_func, param);
1596 ret = GATE_RESULT_OK;
1597 if (ptr_returnvalue)
1598 {
1599 *ptr_returnvalue = (gate_result_t)(gate_intptr_t)entry_ret;
1600 }
1601 return ret;
1602 }
1603
1604 gate_result_t gate_callstack_switch(gate_callstack_context_t* current_to_save,
1605 gate_callstack_context_t* next_to_load)
1606 {
1607 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1608 if (NULL == gate_callstack_switch_impl(current_to_save, next_to_load))
1609 {
1610 ret = GATE_RESULT_FAILED;
1611 }
1612 else
1613 {
1614 ret = GATE_RESULT_OK;
1615 }
1616 return ret;
1617 }
1618
1619 #endif /* GATE_CALLSTACKS_EFI_IMPL */
1620
1621
1622 #if defined(GATE_CALLSTACKS_DOS_IMPL)
1623
1624 #include "gate/platforms.h"
1625 #include "gate/platform/dos/doscallstack.h"
1626
1627
1628 gate_result_t gate_callstack_trace(gate_callstack_address_t* addresses, gate_size_t addresses_count, gate_size_t* addresses_used)
1629 {
1630 GATE_UNUSED_ARG(addresses);
1631 GATE_UNUSED_ARG(addresses_count);
1632 GATE_UNUSED_ARG(addresses_used);
1633 return GATE_RESULT_FAILED;
1634 }
1635
1636 gate_result_t gate_callstack_print(gate_callstack_address_t address, char* buffer, gate_size_t buffer_length, gate_size_t* buffer_used)
1637 {
1638 GATE_UNUSED_ARG(address);
1639 GATE_UNUSED_ARG(buffer);
1640 GATE_UNUSED_ARG(buffer_length);
1641 GATE_UNUSED_ARG(buffer_used);
1642 return GATE_RESULT_FAILED;
1643 }
1644
1645 #define DEFAULT_STACK_SIZE 16384
1646
1647 gate_result_t gate_callstack_create(gate_size_t* ptr_stacksize, void** ptr_callstack)
1648 {
1649 gate_result_t result = GATE_RESULT_OUTOFMEMORY;
1650 gate_size_t para_count;
1651 unsigned segment = 0;
1652 gate_size_t stacksize;
1653
1654 if (!ptr_stacksize || !ptr_callstack)
1655 {
1656 return GATE_RESULT_INVALIDARG;
1657 }
1658 stacksize = *ptr_stacksize;
1659
1660 if (stacksize == 0)
1661 {
1662 stacksize = DEFAULT_STACK_SIZE;
1663 }
1664 if (stacksize > 32768)
1665 {
1666 stacksize = 32768;
1667 }
1668 if (stacksize < 256)
1669 {
1670 stacksize = 256;
1671 }
1672 stacksize = (stacksize + 0x0f) & ~((gate_size_t)0x0f);
1673
1674 para_count = (stacksize + 15) / 16;
1675
1676 result = gate_dos_alloc(para_count, &segment);
1677 if (GATE_SUCCEEDED(result))
1678 {
1679 *ptr_callstack = (void*)gate_dos_farptr(segment, 0);
1680 *ptr_stacksize = stacksize;
1681 }
1682 return result;
1683 }
1684
1685 gate_result_t gate_callstack_destroy(void* ptr_callstack, gate_size_t stacksize)
1686 {
1687 unsigned segment = gate_dos_farptr_seg(ptr_callstack);
1688 GATE_UNUSED_ARG(stacksize);
1689 return gate_dos_dealloc(segment);
1690 }
1691
1692
1693 gate_result_t gate_callstack_run(void* ptr_callstack, gate_size_t stacksize, gate_callstack_context_t* ptr_caller_ctx_to_save,
1694 gate_entrypoint_t entry_func, void* param, gate_result_t* ptr_returnvalue)
1695 {
1696 gate_result_t result;
1697 char __far* ptr_stack_begin = (char __far*)ptr_callstack;
1698 char __far* ptr_stack_end;
1699
1700 if (stacksize == 0)
1701 {
1702 stacksize = DEFAULT_STACK_SIZE;
1703 }
1704 gate_mem_clear(ptr_callstack, stacksize);
1705 ptr_stack_end = ptr_stack_begin + stacksize - 2;
1706
1707
1708 result = gate_dos_callstack_create(ptr_stack_end, ptr_caller_ctx_to_save, entry_func, param);
1709 if (GATE_SUCCEEDED(result))
1710 {
1711 if (ptr_returnvalue)
1712 {
1713 *ptr_returnvalue = result;
1714 }
1715 }
1716 return result;
1717 }
1718
1719 gate_result_t gate_callstack_switch(gate_callstack_context_t* current_to_save,
1720 gate_callstack_context_t* next_to_load)
1721 {
1722 return gate_dos_callstack_switch(current_to_save, next_to_load);
1723 }
1724
1725 #endif /* GATE_CALLSTACKS_DOS_IMPL */
1726
1727
1728
1729 #if defined(GATE_CALLSTACKS_NO_IMPL)
1730
1731 gate_result_t gate_callstack_trace(gate_callstack_address_t* addresses, gate_size_t addresses_count, gate_size_t* addresses_used)
1732 {
1733 (void)addresses;
1734 (void)addresses_count;
1735 (void)addresses_used;
1736 return GATE_RESULT_NOTIMPLEMENTED;
1737 }
1738 gate_result_t gate_callstack_print(gate_callstack_address_t address, char* buffer, gate_size_t buffer_length, gate_size_t* buffer_used)
1739 {
1740 (void)address;
1741 (void)buffer;
1742 (void)buffer_length;
1743 (void)buffer_used;
1744 return GATE_RESULT_NOTIMPLEMENTED;
1745 }
1746
1747 gate_result_t gate_callstack_create(gate_size_t* ptr_stacksize, void** ptr_callstack)
1748 {
1749 (void)ptr_stacksize;
1750 (void)ptr_callstack;
1751 return GATE_RESULT_NOTIMPLEMENTED;
1752 }
1753 gate_result_t gate_callstack_destroy(void* ptr_callstack, gate_size_t stacksize)
1754 {
1755 (void)ptr_callstack;
1756 (void)stacksize;
1757 return GATE_RESULT_NOTIMPLEMENTED;
1758 }
1759 gate_result_t gate_callstack_run(void* ptr_callstack, gate_size_t stacksize, gate_callstack_context_t* ptr_caller_ctx_to_save,
1760 gate_entrypoint_t entry_func, void* param, gate_result_t* ptr_returnvalue)
1761 {
1762 (void)ptr_callstack;
1763 (void)stacksize;
1764 (void)ptr_caller_ctx_to_save;
1765 (void)entry_func;
1766 (void)param;
1767 (void)ptr_returnvalue;
1768 return GATE_RESULT_NOTIMPLEMENTED;
1769 }
1770
1771 gate_result_t gate_callstack_switch(gate_callstack_context_t* current_to_save, gate_callstack_context_t* next_to_load)
1772 {
1773 (void)current_to_save;
1774 (void)next_to_load;
1775 return GATE_RESULT_NOTIMPLEMENTED;
1776 }
1777
1778
1779 #endif /* GATE_CALLSTACKS_NO_IMPL */
1780
1781