[runtime] New profiler API.
[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.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_tls_get_jit_tls ();
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                 guchar *ip;
275
276 #ifdef _WIN64
277                 ip = (guchar *) context.Rip;
278 #else
279                 ip = (guchar *) context.Eip;
280 #endif
281
282                 MONO_PROFILER_RAISE (sample_hit, (ip, &context));
283         }
284 }
285
286 static VOID CALLBACK
287 timer_event_proc (UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
288 {
289         thread_timer_expired ((HANDLE)dwUser);
290 }
291
292 static VOID
293 stop_profiler_timer_event (void)
294 {
295         if (g_timer_event != 0) {
296
297                 timeKillEvent (g_timer_event);
298                 g_timer_event = 0;
299         }
300
301         if (g_timer_main_thread != INVALID_HANDLE_VALUE) {
302
303                 CloseHandle (g_timer_main_thread);
304                 g_timer_main_thread = INVALID_HANDLE_VALUE;
305         }
306 }
307
308 static VOID
309 start_profiler_timer_event (void)
310 {
311         g_return_if_fail (g_timer_main_thread == INVALID_HANDLE_VALUE && g_timer_event == 0);
312
313         TIMECAPS timecaps;
314
315         if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
316                 return;
317
318         g_timer_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ());
319         if (g_timer_main_thread == NULL)
320                 return;
321
322         if (timeBeginPeriod (1) != TIMERR_NOERROR)
323                 return;
324
325         g_timer_event = timeSetEvent (1, 0, (LPTIMECALLBACK)timer_event_proc, (DWORD_PTR)g_timer_main_thread, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
326         if (g_timer_event == 0) {
327                 timeEndPeriod (1);
328                 return;
329         }
330 }
331
332 void
333 mono_runtime_setup_stat_profiler (void)
334 {
335         start_profiler_timer_event ();
336         return;
337 }
338
339 void
340 mono_runtime_shutdown_stat_profiler (void)
341 {
342         stop_profiler_timer_event ();
343         return;
344 }
345
346 gboolean
347 mono_setup_thread_context(DWORD thread_id, MonoContext *mono_context)
348 {
349         HANDLE handle;
350         CONTEXT context;
351
352         g_assert (thread_id != GetCurrentThreadId ());
353
354         handle = OpenThread (THREAD_ALL_ACCESS, FALSE, thread_id);
355         g_assert (handle);
356
357         context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
358
359         if (!GetThreadContext (handle, &context)) {
360                 CloseHandle (handle);
361                 return FALSE;
362         }
363
364         g_assert (context.ContextFlags & CONTEXT_INTEGER);
365         g_assert (context.ContextFlags & CONTEXT_CONTROL);
366
367         memset (mono_context, 0, sizeof (MonoContext));
368         mono_sigctx_to_monoctx (&context, mono_context);
369
370         CloseHandle (handle);
371         return TRUE;
372 }
373 #endif /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */
374
375 gboolean
376 mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info)
377 {
378         DWORD id = mono_thread_info_get_tid (info);
379         MonoJitTlsData *jit_tls;
380         void *domain;
381         MonoLMF *lmf = NULL;
382         gpointer *addr;
383
384         tctx->valid = FALSE;
385         tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = NULL;
386         tctx->unwind_data [MONO_UNWIND_DATA_LMF] = NULL;
387         tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = NULL;
388
389         mono_setup_thread_context(id, &tctx->ctx);
390
391         /* mono_set_jit_tls () sets this */
392         jit_tls = mono_thread_info_tls_get (info, TLS_KEY_JIT_TLS);
393         /* SET_APPDOMAIN () sets this */
394         domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN);
395
396         /*Thread already started to cleanup, can no longer capture unwind state*/
397         if (!jit_tls || !domain)
398                 return FALSE;
399
400         /*
401          * The current LMF address is kept in a separate TLS variable, and its hard to read its value without
402          * arch-specific code. But the address of the TLS variable is stored in another TLS variable which
403          * can be accessed through MonoThreadInfo.
404          */
405         /* mono_set_lmf_addr () sets this */
406         addr = mono_thread_info_tls_get (info, TLS_KEY_LMF_ADDR);
407         if (addr)
408                 lmf = *addr;
409
410         tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain;
411         tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls;
412         tctx->unwind_data [MONO_UNWIND_DATA_LMF] = lmf;
413         tctx->valid = TRUE;
414
415         return TRUE;
416 }