3 * POSIX signal handling support for Mono.
6 * Mono Team (mono-list@lists.ximian.com)
8 * Copyright 2001-2003 Ximian, Inc.
9 * Copyright 2003-2008 Ximian, Inc.
11 * See LICENSE for licensing information.
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/assembly.h>
21 #include <mono/metadata/loader.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/class.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/tokentype.h>
26 #include <mono/metadata/tabledefs.h>
27 #include <mono/metadata/threads.h>
28 #include <mono/metadata/appdomain.h>
29 #include <mono/metadata/debug-helpers.h>
30 #include <mono/metadata/profiler-private.h>
31 #include <mono/metadata/mono-config.h>
32 #include <mono/metadata/environment.h>
33 #include <mono/metadata/mono-debug.h>
34 #include <mono/metadata/gc-internals.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/verify.h>
37 #include <mono/metadata/verify-internals.h>
38 #include <mono/metadata/mempool-internals.h>
39 #include <mono/metadata/attach.h>
40 #include <mono/utils/mono-math.h>
41 #include <mono/utils/mono-compiler.h>
42 #include <mono/utils/mono-counters.h>
43 #include <mono/utils/mono-logger-internals.h>
44 #include <mono/utils/mono-mmap.h>
45 #include <mono/utils/dtrace.h>
48 #include "mini-runtime.h"
49 #include "mini-windows.h"
55 #include "jit-icalls.h"
57 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
61 #define MONO_HANDLER_DELIMITER ','
62 #define MONO_HANDLER_DELIMITER_LEN G_N_ELEMENTS(MONO_HANDLER_DELIMITER)-1
64 #define MONO_HANDLER_ATEXIT_WAIT_KEYPRESS "atexit-waitkeypress"
65 #define MONO_HANDLER_ATEXIT_WAIT_KEYPRESS_LEN G_N_ELEMENTS(MONO_HANDLER_ATEXIT_WAIT_KEYPRESS)-1
67 // Typedefs used to setup handler table.
68 typedef void (*handler
)(void);
76 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
78 * atexit_wait_keypress:
80 * This function is installed as an atexit function making sure that the console is not terminated before the end user has a chance to read the result.
81 * This can be handy in debug scenarios (running from within the debugger) since an exit of the process will close the console window
82 * without giving the end user a chance to look at the output before closed.
85 atexit_wait_keypress (void)
90 printf ("Press any key to continue . . . ");
99 * install_atexit_wait_keypress:
101 * This function installs the wait keypress exit handler.
104 install_atexit_wait_keypress (void)
106 atexit (atexit_wait_keypress
);
113 * install_atexit_wait_keypress:
115 * Not supported on WINAPI family.
118 install_atexit_wait_keypress (void)
123 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
125 // Table describing handlers that can be installed at process startup. Adding a new handler can be done by adding a new item to the table together with an install handler function.
126 const HandlerItem g_handler_items
[] = { { MONO_HANDLER_ATEXIT_WAIT_KEYPRESS
, MONO_HANDLER_ATEXIT_WAIT_KEYPRESS_LEN
, install_atexit_wait_keypress
},
130 * get_handler_arg_len:
131 * @handlers: Get length of next handler.
133 * This function calculates the length of next handler included in argument.
135 * Returns: The length of next handler, if available.
138 get_next_handler_arg_len (const char *handlers
)
140 assert (handlers
!= NULL
);
142 size_t current_len
= 0;
143 const char *handler
= strchr (handlers
, MONO_HANDLER_DELIMITER
);
144 if (handler
!= NULL
) {
145 // Get length of next handler arg.
146 current_len
= (handler
- handlers
);
148 // Consume rest as length of next handler arg.
149 current_len
= strlen (handlers
);
156 * install_custom_handler:
157 * @handlers: Handlers included in --handler argument, example "atexit-waitkeypress,someothercmd,yetanothercmd".
158 * @handler_arg_len: Output, length of consumed handler.
160 * This function installs the next handler included in @handlers parameter.
162 * Returns: TRUE on successful install, FALSE on failure or unrecognized handler.
165 install_custom_handler (const char *handlers
, size_t *handler_arg_len
)
167 gboolean result
= FALSE
;
169 assert (handlers
!= NULL
);
170 assert (handler_arg_len
);
172 *handler_arg_len
= get_next_handler_arg_len (handlers
);
173 for (int current_item
= 0; current_item
< G_N_ELEMENTS (g_handler_items
); ++current_item
) {
174 const HandlerItem
* handler_item
= &g_handler_items
[current_item
];
176 if (handler_item
->cmd
== NULL
)
179 if (*handler_arg_len
== handler_item
->cmd_len
&& strncmp (handlers
, handler_item
->cmd
, *handler_arg_len
) == 0) {
180 assert (handler_item
->handler
!= NULL
);
181 handler_item
->handler ();
190 mono_runtime_install_handlers (void)
192 #ifndef MONO_CROSS_COMPILE
194 win32_seh_set_handler(SIGFPE
, mono_sigfpe_signal_handler
);
195 win32_seh_set_handler(SIGILL
, mono_sigill_signal_handler
);
196 win32_seh_set_handler(SIGSEGV
, mono_sigsegv_signal_handler
);
197 if (mini_get_debug_options ()->handle_sigint
)
198 win32_seh_set_handler(SIGINT
, mono_sigint_signal_handler
);
203 mono_runtime_install_custom_handlers (const char *handlers
)
205 gboolean result
= FALSE
;
207 assert (handlers
!= NULL
);
208 while (*handlers
!= '\0') {
209 size_t handler_arg_len
= 0;
211 result
= install_custom_handler (handlers
, &handler_arg_len
);
212 handlers
+= handler_arg_len
;
214 if (*handlers
== MONO_HANDLER_DELIMITER
)
224 mono_runtime_install_custom_handlers_usage (void)
228 " --handlers=HANDLERS Enable handler support, HANDLERS is a comma\n"
229 " separated list of available handlers to install.\n"
231 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
232 "HANDLERS is composed of:\n"
233 " atexit-waitkeypress Install an atexit handler waiting for a keypress\n"
234 " before exiting process.\n");
236 "No handlers supported on current platform.\n");
237 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
241 mono_runtime_cleanup_handlers (void)
243 #ifndef MONO_CROSS_COMPILE
248 #if G_HAVE_API_SUPPORT (HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
249 /* mono_chain_signal:
251 * Call the original signal handler for the signal given by the arguments, which
252 * should be the same as for a signal handler. Returns TRUE if the original handler
253 * was called, false otherwise.
256 MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal
)
258 /* Set to FALSE to indicate that vectored exception handling should continue to look for handler */
259 MONO_SIG_HANDLER_GET_INFO ()->handled
= FALSE
;
263 #ifndef MONO_CROSS_COMPILE
265 mono_dump_native_crash_info (const char *signal
, void *ctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
)
271 mono_post_native_crash_handler (const char *signal
, void *ctx
, MONO_SIG_HANDLER_INFO_TYPE
*info
, gboolean crash_chaining
)
276 #endif /* !MONO_CROSS_COMPILE */
277 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
279 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
280 static MMRESULT g_timer_event
= 0;
281 static HANDLE g_timer_main_thread
= INVALID_HANDLE_VALUE
;
284 thread_timer_expired (HANDLE thread
)
288 context
.ContextFlags
= CONTEXT_CONTROL
;
289 if (GetThreadContext (thread
, &context
)) {
293 ip
= (guchar
*) context
.Rip
;
295 ip
= (guchar
*) context
.Eip
;
298 MONO_PROFILER_RAISE (sample_hit
, (ip
, &context
));
303 timer_event_proc (UINT uID
, UINT uMsg
, DWORD_PTR dwUser
, DWORD_PTR dw1
, DWORD_PTR dw2
)
305 thread_timer_expired ((HANDLE
)dwUser
);
309 stop_profiler_timer_event (void)
311 if (g_timer_event
!= 0) {
313 timeKillEvent (g_timer_event
);
317 if (g_timer_main_thread
!= INVALID_HANDLE_VALUE
) {
319 CloseHandle (g_timer_main_thread
);
320 g_timer_main_thread
= INVALID_HANDLE_VALUE
;
325 start_profiler_timer_event (void)
327 g_return_if_fail (g_timer_main_thread
== INVALID_HANDLE_VALUE
&& g_timer_event
== 0);
331 if (timeGetDevCaps (&timecaps
, sizeof (timecaps
)) != TIMERR_NOERROR
)
334 g_timer_main_thread
= OpenThread (READ_CONTROL
| THREAD_GET_CONTEXT
, FALSE
, GetCurrentThreadId ());
335 if (g_timer_main_thread
== NULL
)
338 if (timeBeginPeriod (1) != TIMERR_NOERROR
)
341 g_timer_event
= timeSetEvent (1, 0, (LPTIMECALLBACK
)timer_event_proc
, (DWORD_PTR
)g_timer_main_thread
, TIME_PERIODIC
| TIME_KILL_SYNCHRONOUS
);
342 if (g_timer_event
== 0) {
349 mono_runtime_setup_stat_profiler (void)
351 start_profiler_timer_event ();
356 mono_runtime_shutdown_stat_profiler (void)
358 stop_profiler_timer_event ();
363 mono_setup_thread_context(DWORD thread_id
, MonoContext
*mono_context
)
368 g_assert (thread_id
!= GetCurrentThreadId ());
370 handle
= OpenThread (THREAD_ALL_ACCESS
, FALSE
, thread_id
);
373 context
.ContextFlags
= CONTEXT_INTEGER
| CONTEXT_CONTROL
;
375 if (!GetThreadContext (handle
, &context
)) {
376 CloseHandle (handle
);
380 g_assert (context
.ContextFlags
& CONTEXT_INTEGER
);
381 g_assert (context
.ContextFlags
& CONTEXT_CONTROL
);
383 memset (mono_context
, 0, sizeof (MonoContext
));
384 mono_sigctx_to_monoctx (&context
, mono_context
);
386 CloseHandle (handle
);
389 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
392 mono_thread_state_init_from_handle (MonoThreadUnwindState
*tctx
, MonoThreadInfo
*info
, void *sigctx
)
395 tctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = NULL
;
396 tctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = NULL
;
397 tctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = NULL
;
399 if (sigctx
== NULL
) {
400 DWORD id
= mono_thread_info_get_tid (info
);
401 mono_setup_thread_context (id
, &tctx
->ctx
);
403 g_assert (((CONTEXT
*)sigctx
)->ContextFlags
& CONTEXT_INTEGER
);
404 g_assert (((CONTEXT
*)sigctx
)->ContextFlags
& CONTEXT_CONTROL
);
405 mono_sigctx_to_monoctx (sigctx
, &tctx
->ctx
);
408 /* mono_set_jit_tls () sets this */
409 void *jit_tls
= mono_thread_info_tls_get (info
, TLS_KEY_JIT_TLS
);
410 /* SET_APPDOMAIN () sets this */
411 void *domain
= mono_thread_info_tls_get (info
, TLS_KEY_DOMAIN
);
413 /*Thread already started to cleanup, can no longer capture unwind state*/
414 if (!jit_tls
|| !domain
)
418 * The current LMF address is kept in a separate TLS variable, and its hard to read its value without
419 * arch-specific code. But the address of the TLS variable is stored in another TLS variable which
420 * can be accessed through MonoThreadInfo.
422 /* mono_set_lmf_addr () sets this */
424 MonoLMF
**addr
= (MonoLMF
**)mono_thread_info_tls_get (info
, TLS_KEY_LMF_ADDR
);
428 tctx
->unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = domain
;
429 tctx
->unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = jit_tls
;
430 tctx
->unwind_data
[MONO_UNWIND_DATA_LMF
] = lmf
;