Merge pull request #3692 from lateralusX/jlorenss/win-api-family-support-libmono
[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
17 #include <mono/metadata/assembly.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/tabledefs.h>
20 #include <mono/metadata/class.h>
21 #include <mono/metadata/object.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/tabledefs.h>
24 #include <mono/metadata/threads.h>
25 #include <mono/metadata/appdomain.h>
26 #include <mono/metadata/debug-helpers.h>
27 #include <mono/io-layer/io-layer.h>
28 #include "mono/metadata/profiler.h"
29 #include <mono/metadata/profiler-private.h>
30 #include <mono/metadata/mono-config.h>
31 #include <mono/metadata/environment.h>
32 #include <mono/metadata/mono-debug.h>
33 #include <mono/metadata/gc-internals.h>
34 #include <mono/metadata/threads-types.h>
35 #include <mono/metadata/verify.h>
36 #include <mono/metadata/verify-internals.h>
37 #include <mono/metadata/mempool-internals.h>
38 #include <mono/metadata/attach.h>
39 #include <mono/utils/mono-math.h>
40 #include <mono/utils/mono-compiler.h>
41 #include <mono/utils/mono-counters.h>
42 #include <mono/utils/mono-logger-internals.h>
43 #include <mono/utils/mono-mmap.h>
44 #include <mono/utils/dtrace.h>
45
46 #include "mini.h"
47 #include "mini-windows.h"
48 #include <string.h>
49 #include <ctype.h>
50 #include "trace.h"
51 #include "version.h"
52
53 #include "jit-icalls.h"
54
55 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
56 #include <mmsystem.h>
57 #endif
58
59 void
60 mono_runtime_install_handlers (void)
61 {
62 #ifndef MONO_CROSS_COMPILE
63         win32_seh_init();
64         win32_seh_set_handler(SIGFPE, mono_sigfpe_signal_handler);
65         win32_seh_set_handler(SIGILL, mono_sigill_signal_handler);
66         win32_seh_set_handler(SIGSEGV, mono_sigsegv_signal_handler);
67         if (mini_get_debug_options ()->handle_sigint)
68                 win32_seh_set_handler(SIGINT, mono_sigint_signal_handler);
69 #endif
70 }
71
72 void
73 mono_runtime_cleanup_handlers (void)
74 {
75 #ifndef MONO_CROSS_COMPILE
76         win32_seh_cleanup();
77 #endif
78 }
79
80
81 /* mono_chain_signal:
82  *
83  *   Call the original signal handler for the signal given by the arguments, which
84  * should be the same as for a signal handler. Returns TRUE if the original handler
85  * was called, false otherwise.
86  */
87 gboolean
88 MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal)
89 {
90         MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
91         jit_tls->mono_win_chained_exception_needs_run = TRUE;
92         return TRUE;
93 }
94
95 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
96 static MMRESULT g_timer_event = 0;
97 static HANDLE g_timer_main_thread = INVALID_HANDLE_VALUE;
98
99 static VOID
100 thread_timer_expired (HANDLE thread)
101 {
102         CONTEXT context;
103
104         context.ContextFlags = CONTEXT_CONTROL;
105         if (GetThreadContext (thread, &context)) {
106 #ifdef _WIN64
107                 mono_profiler_stat_hit ((guchar *) context.Rip, &context);
108 #else
109                 mono_profiler_stat_hit ((guchar *) context.Eip, &context);
110 #endif
111         }
112 }
113
114 static VOID CALLBACK
115 timer_event_proc (UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
116 {
117         thread_timer_expired ((HANDLE)dwUser);
118 }
119
120 static VOID
121 stop_profiler_timer_event (void)
122 {
123         if (g_timer_event != 0) {
124
125                 timeKillEvent (g_timer_event);
126                 g_timer_event = 0;
127         }
128
129         if (g_timer_main_thread != INVALID_HANDLE_VALUE) {
130
131                 CloseHandle (g_timer_main_thread);
132                 g_timer_main_thread = INVALID_HANDLE_VALUE;
133         }
134 }
135
136 static VOID
137 start_profiler_timer_event (void)
138 {
139         g_return_if_fail (g_timer_main_thread == INVALID_HANDLE_VALUE && g_timer_event == 0);
140
141         TIMECAPS timecaps;
142
143         if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
144                 return;
145
146         g_timer_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ());
147         if (g_timer_main_thread == NULL)
148                 return;
149
150         if (timeBeginPeriod (1) != TIMERR_NOERROR)
151                 return;
152
153         g_timer_event = timeSetEvent (1, 0, (LPTIMECALLBACK)timer_event_proc, (DWORD_PTR)g_timer_main_thread, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
154         if (g_timer_event == 0) {
155                 timeEndPeriod (1);
156                 return;
157         }
158 }
159
160 void
161 mono_runtime_setup_stat_profiler (void)
162 {
163         start_profiler_timer_event ();
164         return;
165 }
166
167 void
168 mono_runtime_shutdown_stat_profiler (void)
169 {
170         stop_profiler_timer_event ();
171         return;
172 }
173
174 gboolean
175 mono_setup_thread_context(DWORD thread_id, MonoContext *mono_context)
176 {
177         HANDLE handle;
178         CONTEXT context;
179
180         g_assert (thread_id != GetCurrentThreadId ());
181
182         handle = OpenThread (THREAD_ALL_ACCESS, FALSE, thread_id);
183         g_assert (handle);
184
185         context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
186
187         if (!GetThreadContext (handle, &context)) {
188                 CloseHandle (handle);
189                 return FALSE;
190         }
191
192         g_assert (context.ContextFlags & CONTEXT_INTEGER);
193         g_assert (context.ContextFlags & CONTEXT_CONTROL);
194
195         memset (mono_context, 0, sizeof (MonoContext));
196         mono_sigctx_to_monoctx (&context, mono_context);
197
198         CloseHandle (handle);
199         return TRUE;
200 }
201 #endif /* G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT) */
202
203 gboolean
204 mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info)
205 {
206         DWORD id = mono_thread_info_get_tid (info);
207         MonoJitTlsData *jit_tls;
208         void *domain;
209         MonoLMF *lmf = NULL;
210         gpointer *addr;
211
212         tctx->valid = FALSE;
213         tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = NULL;
214         tctx->unwind_data [MONO_UNWIND_DATA_LMF] = NULL;
215         tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = NULL;
216
217         mono_setup_thread_context(id, &tctx->ctx);
218
219         /* mono_set_jit_tls () sets this */
220         jit_tls = mono_thread_info_tls_get (info, TLS_KEY_JIT_TLS);
221         /* SET_APPDOMAIN () sets this */
222         domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN);
223
224         /*Thread already started to cleanup, can no longer capture unwind state*/
225         if (!jit_tls || !domain)
226                 return FALSE;
227
228         /*
229          * The current LMF address is kept in a separate TLS variable, and its hard to read its value without
230          * arch-specific code. But the address of the TLS variable is stored in another TLS variable which
231          * can be accessed through MonoThreadInfo.
232          */
233         /* mono_set_lmf_addr () sets this */
234         addr = mono_thread_info_tls_get (info, TLS_KEY_LMF_ADDR);
235         if (addr)
236                 lmf = *addr;
237
238         tctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = domain;
239         tctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls;
240         tctx->unwind_data [MONO_UNWIND_DATA_LMF] = lmf;
241         tctx->valid = TRUE;
242
243         return TRUE;
244 }