Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / mini / mini-windows.c
1 /**
2  * \file
3  * POSIX signal handling support for Mono.
4  *
5  * Authors:
6  *   Mono Team (mono-list@lists.ximian.com)
7  *
8  * Copyright 2001-2003 Ximian, Inc.
9  * Copyright 2003-2008 Ximian, Inc.
10  *
11  * See LICENSE for licensing information.
12  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13  */
14 #include <config.h>
15 #include <signal.h>
16 #include <math.h>
17 #include <conio.h>
18 #include <assert.h>
19
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>
46
47 #include "mini.h"
48 #include "mini-windows.h"
49 #include <string.h>
50 #include <ctype.h>
51 #include "trace.h"
52 #include "version.h"
53
54 #include "jit-icalls.h"
55
56 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
57 #include <mmsystem.h>
58 #endif
59
60 #define MONO_HANDLER_DELIMITER ','
61 #define MONO_HANDLER_DELIMITER_LEN G_N_ELEMENTS(MONO_HANDLER_DELIMITER)-1
62
63 #define MONO_HANDLER_ATEXIT_WAIT_KEYPRESS "atexit-waitkeypress"
64 #define MONO_HANDLER_ATEXIT_WAIT_KEYPRESS_LEN G_N_ELEMENTS(MONO_HANDLER_ATEXIT_WAIT_KEYPRESS)-1
65
66 // Typedefs used to setup handler table.
67 typedef void (*handler)(void);
68
69 typedef struct {
70         const char * cmd;
71         const int cmd_len;
72         handler handler;
73 } HandlerItem;
74
75 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
76 /**
77 * atexit_wait_keypress:
78 *
79 * 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.
80 * This can be handy in debug scenarios (running from within the debugger) since an exit of the process will close the console window
81 * without giving the end user a chance to look at the output before closed.
82 */
83 static void
84 atexit_wait_keypress (void)
85 {
86
87         fflush (stdin);
88
89         printf ("Press any key to continue . . . ");
90         fflush (stdout);
91
92         _getch ();
93
94         return;
95 }
96
97 /**
98 * install_atexit_wait_keypress:
99 *
100 * This function installs the wait keypress exit handler.
101 */
102 static void
103 install_atexit_wait_keypress (void)
104 {
105         atexit (atexit_wait_keypress);
106         return;
107 }
108
109 #else
110
111 /**
112 * install_atexit_wait_keypress:
113 *
114 * Not supported on WINAPI family.
115 */
116 static void
117 install_atexit_wait_keypress (void)
118 {
119         return;
120 }
121
122 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
123
124 // 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.
125 const HandlerItem g_handler_items[] = { { MONO_HANDLER_ATEXIT_WAIT_KEYPRESS, MONO_HANDLER_ATEXIT_WAIT_KEYPRESS_LEN, install_atexit_wait_keypress },
126                                         { NULL, 0, NULL } };
127
128 /**
129  * get_handler_arg_len:
130  * @handlers: Get length of next handler.
131  *
132  * This function calculates the length of next handler included in argument.
133  *
134  * Returns: The length of next handler, if available.
135  */
136 static size_t
137 get_next_handler_arg_len (const char *handlers)
138 {
139         assert (handlers != NULL);
140
141         size_t current_len = 0;
142         const char *handler = strchr (handlers, MONO_HANDLER_DELIMITER);
143         if (handler != NULL) {
144                 // Get length of next handler arg.
145                 current_len = (handler - handlers);
146         } else {
147                 // Consume rest as length of next handler arg.
148                 current_len = strlen (handlers);
149         }
150
151         return current_len;
152 }
153
154 /**
155  * install_custom_handler:
156  * @handlers: Handlers included in --handler argument, example "atexit-waitkeypress,someothercmd,yetanothercmd".
157  * @handler_arg_len: Output, length of consumed handler.
158  *
159  * This function installs the next handler included in @handlers parameter.
160  *
161  * Returns: TRUE on successful install, FALSE on failure or unrecognized handler.
162  */
163 static gboolean
164 install_custom_handler (const char *handlers, size_t *handler_arg_len)
165 {
166         gboolean result = FALSE;
167
168         assert (handlers != NULL);
169         assert (handler_arg_len);
170
171         *handler_arg_len = get_next_handler_arg_len (handlers);
172         for (int current_item = 0; current_item < G_N_ELEMENTS (g_handler_items); ++current_item) {
173                 const HandlerItem * handler_item = &g_handler_items [current_item];
174
175                 if (handler_item->cmd == NULL)
176                         continue;
177
178                 if (*handler_arg_len == handler_item->cmd_len && strncmp (handlers, handler_item->cmd, *handler_arg_len) == 0) {
179                         assert (handler_item->handler != NULL);
180                         handler_item->handler ();
181                         result = TRUE;
182                         break;
183                 }
184         }
185         return result;
186 }
187
188 void
189 mono_runtime_install_handlers (void)
190 {
191 #ifndef MONO_CROSS_COMPILE
192         win32_seh_init();
193         win32_seh_set_handler(SIGFPE, mono_sigfpe_signal_handler);
194         win32_seh_set_handler(SIGILL, mono_sigill_signal_handler);
195         win32_seh_set_handler(SIGSEGV, mono_sigsegv_signal_handler);
196         if (mini_get_debug_options ()->handle_sigint)
197                 win32_seh_set_handler(SIGINT, mono_sigint_signal_handler);
198 #endif
199 }
200
201 gboolean
202 mono_runtime_install_custom_handlers (const char *handlers)
203 {
204         gboolean result = FALSE;
205
206         assert (handlers != NULL);
207         while (*handlers != '\0') {
208                 size_t handler_arg_len = 0;
209
210                 result = install_custom_handler (handlers, &handler_arg_len);
211                 handlers += handler_arg_len;
212
213                 if (*handlers == MONO_HANDLER_DELIMITER)
214                         handlers++;
215                 if (!result)
216                         break;
217         }
218
219         return result;
220 }
221
222 void
223 mono_runtime_install_custom_handlers_usage (void)
224 {
225         fprintf (stdout,
226                  "Custom Handlers:\n"
227                  "   --handlers=HANDLERS            Enable handler support, HANDLERS is a comma\n"
228                  "                                  separated list of available handlers to install.\n"
229                  "\n"
230 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
231                  "HANDLERS is composed of:\n"
232                  "    atexit-waitkeypress           Install an atexit handler waiting for a keypress\n"
233                  "                                  before exiting process.\n");
234 #else
235                  "No handlers supported on current platform.\n");
236 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
237 }
238
239 void
240 mono_runtime_cleanup_handlers (void)
241 {
242 #ifndef MONO_CROSS_COMPILE
243         win32_seh_cleanup();
244 #endif
245 }
246
247
248 /* mono_chain_signal:
249  *
250  *   Call the original signal handler for the signal given by the arguments, which
251  * should be the same as for a signal handler. Returns TRUE if the original handler
252  * was called, false otherwise.
253  */
254 gboolean
255 MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal)
256 {
257         MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
258         jit_tls->mono_win_chained_exception_needs_run = TRUE;
259         return TRUE;
260 }
261
262 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
263 static MMRESULT g_timer_event = 0;
264 static HANDLE g_timer_main_thread = INVALID_HANDLE_VALUE;
265
266 static VOID
267 thread_timer_expired (HANDLE thread)
268 {
269         CONTEXT context;
270
271         context.ContextFlags = CONTEXT_CONTROL;
272         if (GetThreadContext (thread, &context)) {
273                 guchar *ip;
274
275 #ifdef _WIN64
276                 ip = (guchar *) context.Rip;
277 #else
278                 ip = (guchar *) context.Eip;
279 #endif
280
281                 MONO_PROFILER_RAISE (sample_hit, (ip, &context));
282         }
283 }
284
285 static VOID CALLBACK
286 timer_event_proc (UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
287 {
288         thread_timer_expired ((HANDLE)dwUser);
289 }
290
291 static VOID
292 stop_profiler_timer_event (void)
293 {
294         if (g_timer_event != 0) {
295
296                 timeKillEvent (g_timer_event);
297                 g_timer_event = 0;
298         }
299
300         if (g_timer_main_thread != INVALID_HANDLE_VALUE) {
301
302                 CloseHandle (g_timer_main_thread);
303                 g_timer_main_thread = INVALID_HANDLE_VALUE;
304         }
305 }
306
307 static VOID
308 start_profiler_timer_event (void)
309 {
310         g_return_if_fail (g_timer_main_thread == INVALID_HANDLE_VALUE && g_timer_event == 0);
311
312         TIMECAPS timecaps;
313
314         if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
315                 return;
316
317         g_timer_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ());
318         if (g_timer_main_thread == NULL)
319                 return;
320
321         if (timeBeginPeriod (1) != TIMERR_NOERROR)
322                 return;
323
324         g_timer_event = timeSetEvent (1, 0, (LPTIMECALLBACK)timer_event_proc, (DWORD_PTR)g_timer_main_thread, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
325         if (g_timer_event == 0) {
326                 timeEndPeriod (1);
327                 return;
328         }
329 }
330
331 void
332 mono_runtime_setup_stat_profiler (void)
333 {
334         start_profiler_timer_event ();
335         return;
336 }
337
338 void
339 mono_runtime_shutdown_stat_profiler (void)
340 {
341         stop_profiler_timer_event ();
342         return;
343 }
344
345 gboolean
346 mono_setup_thread_context(DWORD thread_id, MonoContext *mono_context)
347 {
348         HANDLE handle;
349         CONTEXT context;
350
351         g_assert (thread_id != GetCurrentThreadId ());
352
353         handle = OpenThread (THREAD_ALL_ACCESS, FALSE, thread_id);
354         g_assert (handle);
355
356         context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
357
358         if (!GetThreadContext (handle, &context)) {
359                 CloseHandle (handle);
360                 return FALSE;
361         }
362
363         g_assert (context.ContextFlags & CONTEXT_INTEGER);
364         g_assert (context.ContextFlags & CONTEXT_CONTROL);
365
366         memset (mono_context, 0, sizeof (MonoContext));
367         mono_sigctx_to_monoctx (&context, mono_context);
368
369         CloseHandle (handle);
370         return TRUE;
371 }
372 #endif /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */
373
374 gboolean
375 mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info)
376 {
377         DWORD id = mono_thread_info_get_tid (info);
378         MonoJitTlsData *jit_tls;
379         void *domain;
380         MonoLMF *lmf = NULL;
381         gpointer *addr;
382
383         tctx->valid = FALSE;
384         tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = NULL;
385         tctx->unwind_data [MONO_UNWIND_DATA_LMF] = NULL;
386         tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = NULL;
387
388         mono_setup_thread_context(id, &tctx->ctx);
389
390         /* mono_set_jit_tls () sets this */
391         jit_tls = mono_thread_info_tls_get (info, TLS_KEY_JIT_TLS);
392         /* SET_APPDOMAIN () sets this */
393         domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN);
394
395         /*Thread already started to cleanup, can no longer capture unwind state*/
396         if (!jit_tls || !domain)
397                 return FALSE;
398
399         /*
400          * The current LMF address is kept in a separate TLS variable, and its hard to read its value without
401          * arch-specific code. But the address of the TLS variable is stored in another TLS variable which
402          * can be accessed through MonoThreadInfo.
403          */
404         /* mono_set_lmf_addr () sets this */
405         addr = mono_thread_info_tls_get (info, TLS_KEY_LMF_ADDR);
406         if (addr)
407                 lmf = *addr;
408
409         tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain;
410         tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls;
411         tctx->unwind_data [MONO_UNWIND_DATA_LMF] = lmf;
412         tctx->valid = TRUE;
413
414         return TRUE;
415 }