@@ -21,20 +21,20 @@ typedef struct {
2121 size_t offset ;
2222} StackTraceBuffer ;
2323
24- bool finit_stack_trace_buffer (StackTraceBuffer * pStackTraceBuffer , size_t size )
25- {
24+ static bool finit_stack_trace_buffer (StackTraceBuffer * pStackTraceBuffer ,
25+ size_t size ) {
2626 char * error_buffer = (char * )malloc (size );
2727 if (error_buffer == NULL ) {
2828 return false;
2929 }
3030 pStackTraceBuffer -> capacity = size ;
3131 pStackTraceBuffer -> offset = 0 ;
3232 pStackTraceBuffer -> buffer = error_buffer ;
33- pStackTraceBuffer -> buffer [0 ] = '0' ;
33+ pStackTraceBuffer -> buffer [0 ] = '\ 0' ;
3434 return true;
3535}
3636
37- void append_to_buffer (StackTraceBuffer * sb , const char * format , ...) {
37+ static void append_to_buffer (StackTraceBuffer * sb , const char * format , ...) {
3838 if (sb -> offset >= sb -> capacity )
3939 return ; // Buffer full
4040
@@ -59,156 +59,151 @@ void append_to_buffer(StackTraceBuffer *sb, const char *format, ...) {
5959
6060static const char * CAML_ERROR_ID = "segfault exception" ;
6161
62- #if defined(_WIN32 ) || defined( _WIN64 )
62+ #if defined(_WIN32 )
6363#define PLATFORM_WINDOWS
64+ #include <dbghelp.h>
6465#include <excpt.h>
6566#include <windows.h>
66- #include <dbghelp.h>
6767
68- void create_stacktrace (StackTraceBuffer * pStackTraceBuffer )
69- {
70- HANDLE process = GetCurrentProcess ();
71- HANDLE thread = GetCurrentThread ();
72- CONTEXT context ;
73- STACKFRAME64 stack ;
74- DWORD machine_type ;
75-
76- RtlCaptureContext (& context );
77-
78- ZeroMemory (& stack , sizeof (STACKFRAME64 ));
79-
80- #ifdef _M_IX86
81- machine_type = IMAGE_FILE_MACHINE_I386 ;
82- stack .AddrPC .Offset = context .Eip ;
83- stack .AddrFrame .Offset = context .Ebp ;
84- stack .AddrStack .Offset = context .Esp ;
85- #elif _M_X64
86- machine_type = IMAGE_FILE_MACHINE_AMD64 ;
87- stack .AddrPC .Offset = context .Rip ;
88- stack .AddrFrame .Offset = context .Rsp ;
89- stack .AddrStack .Offset = context .Rsp ;
90- #elif _M_ARM64
91- machine_type = IMAGE_FILE_MACHINE_ARM64 ;
92- stack .AddrPC .Offset = context .Pc ;
93- stack .AddrFrame .Offset = context .Fp ;
94- stack .AddrStack .Offset = context .Sp ;
68+ // Stacktrace collection inspired by
69+ // https://smhk.net/note/2025/03/c-stack-trace-in-windows/
70+ static void create_stacktrace (StackTraceBuffer * pStackTraceBuffer ) {
71+ HANDLE process = GetCurrentProcess ();
72+ HANDLE thread = GetCurrentThread ();
73+ CONTEXT context ;
74+ STACKFRAME64 stack ;
75+ DWORD machine_type ;
76+
77+ RtlCaptureContext (& context );
78+
79+ ZeroMemory (& stack , sizeof (STACKFRAME64 ));
80+
81+ #if defined(_M_IX86 ) || defined(__i386__ )
82+ machine_type = IMAGE_FILE_MACHINE_I386 ;
83+ stack .AddrPC .Offset = context .Eip ;
84+ stack .AddrFrame .Offset = context .Ebp ;
85+ stack .AddrStack .Offset = context .Esp ;
86+ #elif defined(_M_X64 ) || defined(__x86_64__ )
87+ machine_type = IMAGE_FILE_MACHINE_AMD64 ;
88+ stack .AddrPC .Offset = context .Rip ;
89+ stack .AddrFrame .Offset = context .Rsp ;
90+ stack .AddrStack .Offset = context .Rsp ;
91+ #elif defined(_M_ARM64 ) || defined(__aarch64__ )
92+ machine_type = IMAGE_FILE_MACHINE_ARM64 ;
93+ stack .AddrPC .Offset = context .Pc ;
94+ stack .AddrFrame .Offset = context .Fp ;
95+ stack .AddrStack .Offset = context .Sp ;
9596#else
9697#error "Unsupported platform"
9798#endif
9899
99- stack .AddrPC .Mode = AddrModeFlat ;
100- stack .AddrFrame .Mode = AddrModeFlat ;
101- stack .AddrStack .Mode = AddrModeFlat ;
102-
103- SymInitialize (process , NULL , TRUE);
104- SymSetOptions (SYMOPT_LOAD_LINES | SYMOPT_UNDNAME );
105-
106- append_to_buffer (pStackTraceBuffer , "Stack trace:\n" );
107- append_to_buffer (pStackTraceBuffer , " %-40s %-18s %s\n" , "Function" , "Address" , "Line" );
108- append_to_buffer (pStackTraceBuffer , " %-40s %-18s %s\n" , "--------" , "-------" , "----" );
109-
110- while (StackWalk64 (
111- machine_type ,
112- process ,
113- thread ,
114- & stack ,
115- & context ,
116- NULL ,
117- SymFunctionTableAccess64 ,
118- SymGetModuleBase64 ,
119- NULL )) {
120- if (stack .AddrPC .Offset == 0 )
121- break ;
122-
123- DWORD64 symbol_addr = stack .AddrPC .Offset ;
124- DWORD64 displacement = 0 ;
125- char symbol_buffer [sizeof (SYMBOL_INFO ) + MAX_SYM_NAME * sizeof (TCHAR )] = {0 };
126- SYMBOL_INFO * symbol = (SYMBOL_INFO * )symbol_buffer ;
127- symbol -> SizeOfStruct = sizeof (SYMBOL_INFO );
128- symbol -> MaxNameLen = MAX_SYM_NAME ;
129-
130- // Get line information
131- IMAGEHLP_LINE64 line = {0 };
132- line .SizeOfStruct = sizeof (IMAGEHLP_LINE64 );
133- DWORD line_displacement = 0 ;
134- BOOL has_line = SymGetLineFromAddr64 (process , symbol_addr , & line_displacement , & line );
135-
136- char function_name [MAX_SYM_NAME ] = "Unknown" ;
137- if (SymFromAddr (process , symbol_addr , & displacement , symbol )) {
138- strncpy (function_name , symbol -> Name , MAX_SYM_NAME - 1 );
139- function_name [MAX_SYM_NAME - 1 ] = '\0' ; // Ensure null termination
140- }
141- // Format line information
142- char line_info [256 ] = "Unknown" ;
143- if (has_line ) {
144- snprintf (line_info , sizeof (line_info ), "%s:%lu" , line .FileName , line .LineNumber );
145- }
146-
147- // Print with better alignment using format specifiers
148- append_to_buffer (pStackTraceBuffer ,
149- " %-40.40s 0x%016llX %s\n" ,
150- function_name ,
151- symbol_addr ,
152- line_info );
153- append_to_buffer (pStackTraceBuffer , "\0" );
154-
100+ stack .AddrPC .Mode = AddrModeFlat ;
101+ stack .AddrFrame .Mode = AddrModeFlat ;
102+ stack .AddrStack .Mode = AddrModeFlat ;
103+
104+ SymInitialize (process , NULL , TRUE);
105+ SymSetOptions (SYMOPT_LOAD_LINES | SYMOPT_UNDNAME );
106+
107+ append_to_buffer (pStackTraceBuffer , "Stack trace:\n" );
108+ append_to_buffer (pStackTraceBuffer , " %-40s %-18s %s\n" , "Function" ,
109+ "Address" , "Line" );
110+ append_to_buffer (pStackTraceBuffer , " %-40s %-18s %s\n" , "--------" ,
111+ "-------" , "----" );
112+
113+ while (StackWalk64 (machine_type , process , thread , & stack , & context , NULL ,
114+ SymFunctionTableAccess64 , SymGetModuleBase64 , NULL )) {
115+ if (stack .AddrPC .Offset == 0 )
116+ break ;
117+
118+ DWORD64 symbol_addr = stack .AddrPC .Offset ;
119+ DWORD64 displacement = 0 ;
120+ _Alignas(SYMBOL_INFO * )
121+ symbol_buffer [sizeof (SYMBOL_INFO ) + MAX_SYM_NAME * sizeof (TCHAR )] = {0 };
122+ SYMBOL_INFO * symbol = (SYMBOL_INFO * )symbol_buffer ;
123+ symbol -> SizeOfStruct = sizeof (SYMBOL_INFO );
124+ symbol -> MaxNameLen = MAX_SYM_NAME ;
125+
126+ // Get line information
127+ IMAGEHLP_LINE64 line = {0 };
128+ line .SizeOfStruct = sizeof (IMAGEHLP_LINE64 );
129+ DWORD line_displacement = 0 ;
130+ BOOL has_line =
131+ SymGetLineFromAddr64 (process , symbol_addr , & line_displacement , & line );
132+
133+ char function_name [MAX_SYM_NAME ] = "Unknown" ;
134+ if (SymFromAddr (process , symbol_addr , & displacement , symbol )) {
135+ strncpy (function_name , symbol -> Name , MAX_SYM_NAME - 1 );
136+ function_name [MAX_SYM_NAME - 1 ] = '\0' ; // Ensure null termination
137+ }
138+ // Format line information
139+ char line_info [256 ] = "Unknown" ;
140+ if (has_line ) {
141+ snprintf (line_info , sizeof (line_info ), "%s:%lu" , line .FileName ,
142+ line .LineNumber );
155143 }
156144
157- SymCleanup (process );
158- }
145+ // Print with better alignment using format specifiers
146+ append_to_buffer (pStackTraceBuffer , " %-40.40s 0x%016llX %s\n" ,
147+ function_name , symbol_addr , line_info );
148+ append_to_buffer (pStackTraceBuffer , "\0" );
149+ }
159150
151+ SymCleanup (process );
152+ }
160153
161154LONG WINAPI windows_exception_handler (PEXCEPTION_POINTERS pExceptionInfo ) {
162- const DWORD exceptionCode = pExceptionInfo -> ExceptionRecord -> ExceptionCode ;
163- switch (exceptionCode ) {
164- case EXCEPTION_ACCESS_VIOLATION :
165- {
166- void * faulting_address = (void * )pExceptionInfo -> ExceptionRecord -> ExceptionInformation [1 ];
167- StackTraceBuffer stack_trace_buffer ;
168- if (!finit_stack_trace_buffer (& stack_trace_buffer , buffer_size ))
169- {
170- caml_failwith ("Can't create stack trace buffer" );
171- return EXCEPTION_CONTINUE_SEARCH ;
172- }
173- create_stacktrace (& stack_trace_buffer );
174-
175- caml_raise_with_string (* caml_named_value (CAML_ERROR_ID ), stack_trace_buffer .buffer );
176- free (stack_trace_buffer .buffer );
177- ExitProcess (STATUS_ACCESS_VIOLATION );
178- }
179- default : break ;
155+ const DWORD exceptionCode = pExceptionInfo -> ExceptionRecord -> ExceptionCode ;
156+ switch (exceptionCode ) {
157+ case EXCEPTION_ACCESS_VIOLATION : {
158+ void * faulting_address =
159+ (void * )pExceptionInfo -> ExceptionRecord -> ExceptionInformation [1 ];
160+ StackTraceBuffer stack_trace_buffer ;
161+ if (!finit_stack_trace_buffer (& stack_trace_buffer , buffer_size )) {
162+ caml_failwith ("Can't create stack trace buffer" );
163+ return EXCEPTION_CONTINUE_SEARCH ;
180164 }
181- return EXCEPTION_CONTINUE_SEARCH ;
165+ create_stacktrace (& stack_trace_buffer );
166+
167+ caml_raise_with_string (* caml_named_value (CAML_ERROR_ID ),
168+ stack_trace_buffer .buffer );
169+ free (stack_trace_buffer .buffer );
170+ ExitProcess (STATUS_ACCESS_VIOLATION );
171+ }
172+ default :
173+ break ;
174+ }
175+ return EXCEPTION_CONTINUE_SEARCH ;
182176}
183177#else
184178#define PLATFORM_UNIX
185- #include <signal.h>
186179#include <execinfo.h>
180+ #include <signal.h>
187181#include <stdlib.h>
188182#include <unistd.h>
189183
190- void unix_signal_handler (int sig , siginfo_t * si , void * unused ) {
184+ #define STACK_TRACE_LENGTH 20
185+
186+ static void unix_signal_handler (int sig , siginfo_t * si , void * unused ) {
191187
192188 StackTraceBuffer stack_trace_buffer ;
193189 if (!finit_stack_trace_buffer (& stack_trace_buffer , buffer_size )) {
194190 caml_failwith ("Can't create stack trace buffer" );
195191 return ;
196192 }
197193
198- void * trace [20 ];
199- size_t trace_size = backtrace (trace , 20 );
194+ void * trace [STACK_TRACE_LENGTH ];
195+ size_t trace_size = backtrace (trace , STACK_TRACE_LENGTH );
200196
201- if (trace_size == 0 )
202- {
197+ if (trace_size == 0 ) {
203198 caml_failwith ("Couldn't get backtrace" );
204199 return ;
205200 }
206201
207- append_to_buffer (& stack_trace_buffer , "Caught Violation access, here's stack trace:\n" );
208-
209- char * * pSymbols = backtrace_symbols ( trace , trace_size );
210- for ( int i = 0 ; i < trace_size ; ++ i )
211- {
202+ append_to_buffer (& stack_trace_buffer ,
203+ "Caught Violation access, here's stack trace:\n" );
204+
205+ char * * pSymbols = backtrace_symbols ( trace , trace_size );
206+ for ( int i = 0 ; i < trace_size ; ++ i ) {
212207 append_to_buffer (& stack_trace_buffer , "%s\n" , pSymbols [i ]);
213208 }
214209 free (pSymbols );
@@ -219,9 +214,7 @@ void unix_signal_handler(int sig, siginfo_t *si, void *unused) {
219214}
220215#endif
221216
222-
223- CAMLprim value caml_setup_stub_exception_handler ()
224- {
217+ CAMLprim value caml_setup_stub_exception_handler (void ) {
225218 CAMLparam0 ();
226219#ifdef PLATFORM_WINDOWS
227220 AddVectoredExceptionHandler (1 , windows_exception_handler );
0 commit comments