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