1 /**
2 * \file
3 * generic exception support
4 *
5 * Authors:
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Mono Team (mono-list@lists.ximian.com)
8 *
9 * Copyright 2001-2003 Ximian, Inc.
10 * Copyright 2003-2008 Novell, Inc.
11 * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 */
14
15 #include <config.h>
16 #include <glib.h>
17 #include <string.h>
18
19 #ifdef HAVE_SIGNAL_H
20 #include <signal.h>
21 #endif
22
23 #ifdef HAVE_EXECINFO_H
24 #include <execinfo.h>
25 #endif
26
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
29 #endif
30
31 #ifdef HAVE_SYS_WAIT_H
32 #include <sys/wait.h>
33 #endif
34
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38
39 #ifdef HAVE_SYS_SYSCALL_H
40 #include <sys/syscall.h>
41 #endif
42
43 #ifdef HAVE_SYS_PRCTL_H
44 #include <sys/prctl.h>
45 #endif
46
47 #ifdef HAVE_UNWIND_H
48 #include <unwind.h>
49 #endif
50
51 #include <mono/metadata/appdomain.h>
52 #include <mono/metadata/tabledefs.h>
53 #include <mono/metadata/threads.h>
54 #include <mono/metadata/threads-types.h>
55 #include <mono/metadata/debug-helpers.h>
56 #include <mono/metadata/exception.h>
57 #include <mono/metadata/exception-internals.h>
58 #include <mono/metadata/object-internals.h>
59 #include <mono/metadata/reflection-internals.h>
60 #include <mono/metadata/gc-internals.h>
61 #include <mono/metadata/debug-internals.h>
62 #include <mono/metadata/mono-debug.h>
63 #include <mono/metadata/profiler-private.h>
64 #include <mono/metadata/mono-endian.h>
65 #include <mono/metadata/environment.h>
66 #include <mono/metadata/mono-mlist.h>
67 #include <mono/utils/mono-merp.h>
68 #include <mono/utils/mono-mmap.h>
69 #include <mono/utils/mono-logger-internals.h>
70 #include <mono/utils/mono-error.h>
71 #include <mono/utils/mono-error-internals.h>
72
73 #include "mini.h"
74 #include "trace.h"
75 #include "debugger-agent.h"
76 #include "seq-points.h"
77 #include "llvm-runtime.h"
78 #include "mini-llvm.h"
79 #include "aot-runtime.h"
80 #include "mini-runtime.h"
81 #include "interp/interp.h"
82
83 #ifdef ENABLE_LLVM
84 #include "mini-llvm-cpp.h"
85 #endif
86
87 #ifdef TARGET_ARM
88 #include "mini-arm.h"
89 #endif
90
91 #ifndef MONO_ARCH_CONTEXT_DEF
92 #define MONO_ARCH_CONTEXT_DEF
93 #endif
94
95 /*
96 * Raw frame information is stored in MonoException.trace_ips as an IntPtr[].
97 * This structure represents one entry.
98 * This should consists of pointers only.
99 */
100 typedef struct
101 {
102 gpointer ip;
103 gpointer generic_info;
104 /* Only for interpreter frames */
105 MonoJitInfo *ji;
106 } ExceptionTraceIp;
107
108 /* Number of words in trace_ips belonging to one entry */
109 #define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer))
110
111 static gpointer restore_context_func, call_filter_func;
112 static gpointer throw_exception_func, rethrow_exception_func;
113 static gpointer throw_corlib_exception_func;
114
115 static gpointer try_more_restore_tramp = NULL;
116 static gpointer restore_stack_protection_tramp = NULL;
117
118 static void try_more_restore (void);
119 static void restore_stack_protection (void);
120 static void mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data);
121 static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx);
122 static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data);
123 static gboolean mono_current_thread_has_handle_block_guard (void);
124 static gboolean mono_install_handler_block_guard (MonoThreadUnwindState *ctx);
125
126 static gboolean
first_managed(MonoStackFrameInfo * frame,MonoContext * ctx,gpointer addr)127 first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr)
128 {
129 gpointer **data = (gpointer **)addr;
130
131 if (!frame->managed)
132 return FALSE;
133
134 if (!ctx) {
135 // FIXME: Happens with llvm_only
136 *data = NULL;
137 return TRUE;
138 }
139
140 *data = MONO_CONTEXT_GET_SP (ctx);
141 g_assert (*data);
142 return TRUE;
143 }
144
145 static gpointer
mono_thread_get_managed_sp(void)146 mono_thread_get_managed_sp (void)
147 {
148 gpointer addr = NULL;
149 mono_walk_stack (first_managed, MONO_UNWIND_SIGNAL_SAFE, &addr);
150 return addr;
151 }
152
153 static inline void
mini_clear_abort_threshold(void)154 mini_clear_abort_threshold (void)
155 {
156 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
157 jit_tls->abort_exc_stack_threshold = NULL;
158 }
159
160 static inline void
mini_set_abort_threshold(MonoContext * ctx)161 mini_set_abort_threshold (MonoContext *ctx)
162 {
163 gpointer sp = MONO_CONTEXT_GET_SP (ctx);
164 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
165 // Only move it up, to avoid thrown/caught
166 // exceptions lower in the stack from triggering
167 // a rethrow
168 gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold;
169 if (!jit_tls->abort_exc_stack_threshold || above_threshold) {
170 jit_tls->abort_exc_stack_threshold = sp;
171 }
172 }
173
174 // Note: In the case that the frame is above where the thread abort
175 // was set we bump the threshold so that functions called from the new,
176 // higher threshold don't trigger the thread abort exception
177 static inline gboolean
mini_above_abort_threshold(void)178 mini_above_abort_threshold (void)
179 {
180 gpointer sp = mono_thread_get_managed_sp ();
181 MonoJitTlsData *jit_tls = (MonoJitTlsData*) mono_tls_get_jit_tls ();
182
183 if (!sp)
184 return TRUE;
185
186 gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold;
187
188 if (above_threshold)
189 jit_tls->abort_exc_stack_threshold = sp;
190
191 return above_threshold;
192 }
193
194 static int
mono_get_seq_point_for_native_offset(MonoDomain * domain,MonoMethod * method,gint32 native_offset)195 mono_get_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset)
196 {
197 SeqPoint sp;
198 if (mono_find_prev_seq_point_for_native_offset (domain, method, native_offset, NULL, &sp))
199 return sp.il_offset;
200 return -1;
201 }
202
203 void
mono_exceptions_init(void)204 mono_exceptions_init (void)
205 {
206 MonoRuntimeExceptionHandlingCallbacks cbs;
207 if (mono_aot_only) {
208 restore_context_func = mono_aot_get_trampoline ("restore_context");
209 call_filter_func = mono_aot_get_trampoline ("call_filter");
210 throw_exception_func = mono_aot_get_trampoline ("throw_exception");
211 rethrow_exception_func = mono_aot_get_trampoline ("rethrow_exception");
212 } else {
213 MonoTrampInfo *info;
214
215 restore_context_func = mono_arch_get_restore_context (&info, FALSE);
216 mono_tramp_info_register (info, NULL);
217 call_filter_func = mono_arch_get_call_filter (&info, FALSE);
218 mono_tramp_info_register (info, NULL);
219 throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
220 mono_tramp_info_register (info, NULL);
221 rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
222 mono_tramp_info_register (info, NULL);
223 }
224 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
225 if (!mono_llvm_only) {
226 try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
227 restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
228 }
229 #endif
230
231 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
232 mono_arch_exceptions_init ();
233 #endif
234 if (mono_use_interpreter)
235 cbs.mono_walk_stack_with_ctx = mini_get_interp_callbacks ()->walk_stack_with_ctx;
236 else
237 cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx;
238
239 cbs.mono_walk_stack_with_state = mono_walk_stack_with_state;
240
241 if (mono_llvm_only) {
242 cbs.mono_raise_exception = mono_llvm_raise_exception;
243 cbs.mono_reraise_exception = mono_llvm_reraise_exception;
244 } else {
245 cbs.mono_raise_exception = (void (*)(MonoException *))mono_get_throw_exception ();
246 cbs.mono_reraise_exception = (void (*)(MonoException *))mono_get_rethrow_exception ();
247 }
248 cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
249 cbs.mono_exception_walk_trace = mono_exception_walk_trace;
250 cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
251 cbs.mono_current_thread_has_handle_block_guard = mono_current_thread_has_handle_block_guard;
252 cbs.mono_clear_abort_threshold = mini_clear_abort_threshold;
253 cbs.mono_above_abort_threshold = mini_above_abort_threshold;
254 mono_install_eh_callbacks (&cbs);
255 mono_install_get_seq_point (mono_get_seq_point_for_native_offset);
256 }
257
258 gpointer
mono_get_throw_exception(void)259 mono_get_throw_exception (void)
260 {
261 g_assert (throw_exception_func);
262 return throw_exception_func;
263 }
264
265 gpointer
mono_get_rethrow_exception(void)266 mono_get_rethrow_exception (void)
267 {
268 g_assert (rethrow_exception_func);
269 return rethrow_exception_func;
270 }
271
272 gpointer
mono_get_call_filter(void)273 mono_get_call_filter (void)
274 {
275 g_assert (call_filter_func);
276 return call_filter_func;
277 }
278
279 gpointer
mono_get_restore_context(void)280 mono_get_restore_context (void)
281 {
282 g_assert (restore_context_func);
283 return restore_context_func;
284 }
285
286 gpointer
mono_get_throw_corlib_exception(void)287 mono_get_throw_corlib_exception (void)
288 {
289 gpointer code = NULL;
290 MonoTrampInfo *info;
291
292 /* This depends on corlib classes so cannot be inited in mono_exceptions_init () */
293 if (throw_corlib_exception_func)
294 return throw_corlib_exception_func;
295
296 if (mono_aot_only)
297 code = mono_aot_get_trampoline ("throw_corlib_exception");
298 else {
299 code = mono_arch_get_throw_corlib_exception (&info, FALSE);
300 mono_tramp_info_register (info, NULL);
301 }
302
303 mono_memory_barrier ();
304
305 throw_corlib_exception_func = code;
306
307 return throw_corlib_exception_func;
308 }
309
310 /*
311 * mono_get_throw_exception_addr:
312 *
313 * Return an address which stores the result of
314 * mono_get_throw_exception.
315 */
316 gpointer
mono_get_throw_exception_addr(void)317 mono_get_throw_exception_addr (void)
318 {
319 return &throw_exception_func;
320 }
321
322 static gboolean
is_address_protected(MonoJitInfo * ji,MonoJitExceptionInfo * ei,gpointer ip)323 is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip)
324 {
325 MonoTryBlockHoleTableJitInfo *table;
326 int i;
327 guint32 offset;
328 guint16 clause;
329
330 if (ei->try_start > ip || ip >= ei->try_end)
331 return FALSE;
332
333 if (!ji->has_try_block_holes)
334 return TRUE;
335
336 table = mono_jit_info_get_try_block_hole_table_info (ji);
337 offset = (guint32)((char*)ip - (char*)ji->code_start);
338 clause = (guint16)(ei - ji->clauses);
339 g_assert (clause < ji->num_clauses);
340
341 for (i = 0; i < table->num_holes; ++i) {
342 MonoTryBlockHoleJitInfo *hole = &table->holes [i];
343 if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset)
344 return FALSE;
345 }
346 return TRUE;
347 }
348
349 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
350
351 #if 0
352 static gboolean show_native_addresses = TRUE;
353 #else
354 static gboolean show_native_addresses = FALSE;
355 #endif
356
357 static _Unwind_Reason_Code
build_stack_trace(struct _Unwind_Context * frame_ctx,void * state)358 build_stack_trace (struct _Unwind_Context *frame_ctx, void *state)
359 {
360 MonoDomain *domain = mono_domain_get ();
361 uintptr_t ip = _Unwind_GetIP (frame_ctx);
362
363 if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) {
364 GList **trace_ips = (GList **)state;
365 *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip);
366 }
367
368 return _URC_NO_REASON;
369 }
370
371 static GSList*
get_unwind_backtrace(void)372 get_unwind_backtrace (void)
373 {
374 GSList *ips = NULL;
375
376 _Unwind_Backtrace (build_stack_trace, &ips);
377
378 return g_slist_reverse (ips);
379 }
380
381 #else
382
383 static GSList*
get_unwind_backtrace(void)384 get_unwind_backtrace (void)
385 {
386 return NULL;
387 }
388
389 #endif
390
391 static gboolean
arch_unwind_frame(MonoDomain * domain,MonoJitTlsData * jit_tls,MonoJitInfo * ji,MonoContext * ctx,MonoContext * new_ctx,MonoLMF ** lmf,mgreg_t ** save_locations,StackFrameInfo * frame)392 arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls,
393 MonoJitInfo *ji, MonoContext *ctx,
394 MonoContext *new_ctx, MonoLMF **lmf,
395 mgreg_t **save_locations,
396 StackFrameInfo *frame)
397 {
398 if (!ji && *lmf) {
399 if (((guint64)(*lmf)->previous_lmf) & 2) {
400 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
401
402 memset (frame, 0, sizeof (StackFrameInfo));
403 frame->ji = ji;
404
405 *new_ctx = *ctx;
406
407 if (ext->debugger_invoke) {
408 /*
409 * This LMF entry is created by the soft debug code to mark transitions to
410 * managed code done during invokes.
411 */
412 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
413 memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
414 } else if (ext->interp_exit) {
415 frame->type = FRAME_TYPE_INTERP_TO_MANAGED;
416 frame->interp_exit_data = ext->interp_exit_data;
417 } else {
418 g_assert_not_reached ();
419 }
420
421 *lmf = (MonoLMF *)(((guint64)(*lmf)->previous_lmf) & ~3);
422
423 return TRUE;
424 }
425 }
426
427 return mono_arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
428 }
429
430 /*
431 * find_jit_info:
432 *
433 * Translate between the mono_arch_unwind_frame function and the old API.
434 */
435 static MonoJitInfo *
find_jit_info(MonoDomain * domain,MonoJitTlsData * jit_tls,MonoJitInfo * res,MonoJitInfo * prev_ji,MonoContext * ctx,MonoContext * new_ctx,MonoLMF ** lmf,gboolean * managed)436 find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
437 MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
438 {
439 StackFrameInfo frame;
440 MonoJitInfo *ji;
441 gboolean err;
442 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
443
444 /* Avoid costly table lookup during stack overflow */
445 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
446 ji = prev_ji;
447 else
448 ji = mini_jit_info_table_find (domain, (char *)ip, NULL);
449
450 if (managed)
451 *managed = FALSE;
452
453 err = arch_unwind_frame (domain, jit_tls, ji, ctx, new_ctx, lmf, NULL, &frame);
454 if (!err)
455 return (MonoJitInfo *)-1;
456
457 if (*lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
458 /*
459 * Remove any unused lmf.
460 * Mask out the lower bits which might be used to hold additional information.
461 */
462 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(SIZEOF_VOID_P -1));
463 }
464
465 /* Convert between the new and the old APIs */
466 switch (frame.type) {
467 case FRAME_TYPE_MANAGED:
468 if (managed)
469 *managed = TRUE;
470 return frame.ji;
471 case FRAME_TYPE_TRAMPOLINE:
472 return frame.ji;
473 case FRAME_TYPE_MANAGED_TO_NATIVE:
474 if (frame.ji)
475 return frame.ji;
476 else {
477 memset (res, 0, sizeof (MonoJitInfo));
478 res->d.method = frame.method;
479 return res;
480 }
481 case FRAME_TYPE_DEBUGGER_INVOKE: {
482 MonoContext tmp_ctx;
483
484 /*
485 * The normal exception handling code can't handle this frame, so just
486 * skip it.
487 */
488 ji = find_jit_info (domain, jit_tls, res, NULL, new_ctx, &tmp_ctx, lmf, managed);
489 memcpy (new_ctx, &tmp_ctx, sizeof (MonoContext));
490 return ji;
491 }
492 default:
493 g_assert_not_reached ();
494 return NULL;
495 }
496 }
497
498 /* mono_find_jit_info:
499 *
500 * This function is used to gather information from @ctx. It return the
501 * MonoJitInfo of the corresponding function, unwinds one stack frame and
502 * stores the resulting context into @new_ctx. It also stores a string
503 * describing the stack location into @trace (if not NULL), and modifies
504 * the @lmf if necessary. @native_offset return the IP offset from the
505 * start of the function or -1 if that info is not available.
506 */
507 MonoJitInfo *
mono_find_jit_info(MonoDomain * domain,MonoJitTlsData * jit_tls,MonoJitInfo * res,MonoJitInfo * prev_ji,MonoContext * ctx,MonoContext * new_ctx,char ** trace,MonoLMF ** lmf,int * native_offset,gboolean * managed)508 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
509 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
510 gboolean *managed)
511 {
512 gboolean managed2;
513 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
514 MonoJitInfo *ji;
515 MonoMethod *method = NULL;
516
517 if (trace)
518 *trace = NULL;
519
520 if (native_offset)
521 *native_offset = -1;
522
523 if (managed)
524 *managed = FALSE;
525
526 ji = find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, lmf, &managed2);
527
528 if (ji == (gpointer)-1)
529 return ji;
530
531 if (ji && !ji->is_trampoline)
532 method = jinfo_get_method (ji);
533
534 if (managed2 || (method && method->wrapper_type)) {
535 const char *real_ip, *start;
536 gint32 offset;
537
538 start = (const char *)ji->code_start;
539 if (!managed2)
540 /* ctx->ip points into native code */
541 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
542 else
543 real_ip = (const char*)ip;
544
545 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
546 offset = real_ip - start;
547 else
548 offset = -1;
549
550 if (native_offset)
551 *native_offset = offset;
552
553 if (managed)
554 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
555 *managed = TRUE;
556
557 if (trace)
558 *trace = mono_debug_print_stack_frame (method, offset, domain);
559 } else {
560 if (trace) {
561 char *fname = mono_method_full_name (jinfo_get_method (res), TRUE);
562 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
563 g_free (fname);
564 }
565 }
566
567 return ji;
568 }
569
570 /*
571 * mono_find_jit_info_ext:
572 *
573 * A version of mono_find_jit_info which returns all data in the StackFrameInfo
574 * structure.
575 * A note about frames of type FRAME_TYPE_MANAGED_TO_NATIVE:
576 * - These frames are used to mark managed-to-native transitions, so CTX will refer to native
577 * code, and new_ctx will refer to the last managed frame. The caller should unwind once more
578 * to obtain the last managed frame.
579 * If SAVE_LOCATIONS is not NULL, it should point to an array of size MONO_MAX_IREGS.
580 * On return, it will be filled with the locations where callee saved registers are saved
581 * by the current frame. This is returned outside of StackFrameInfo because it can be
582 * quite large on some platforms.
583 * If ASYNC true, this function will be async safe, but some fields of frame and frame->ji will
584 * not be set.
585 */
586 gboolean
mono_find_jit_info_ext(MonoDomain * domain,MonoJitTlsData * jit_tls,MonoJitInfo * prev_ji,MonoContext * ctx,MonoContext * new_ctx,char ** trace,MonoLMF ** lmf,mgreg_t ** save_locations,StackFrameInfo * frame)587 mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
588 MonoJitInfo *prev_ji, MonoContext *ctx,
589 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
590 mgreg_t **save_locations,
591 StackFrameInfo *frame)
592 {
593 gboolean err;
594 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
595 MonoJitInfo *ji;
596 MonoDomain *target_domain = domain;
597 MonoMethod *method = NULL;
598 gboolean async = mono_thread_info_is_async_context ();
599
600 if (trace)
601 *trace = NULL;
602
603 /* Avoid costly table lookup during stack overflow */
604 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
605 ji = prev_ji;
606 else
607 ji = mini_jit_info_table_find (domain, (char *)ip, &target_domain);
608
609 if (!target_domain)
610 target_domain = domain;
611
612 if (save_locations)
613 memset (save_locations, 0, MONO_MAX_IREGS * sizeof (mgreg_t*));
614
615 err = arch_unwind_frame (target_domain, jit_tls, ji, ctx, new_ctx, lmf, save_locations, frame);
616 if (!err)
617 return FALSE;
618
619 if (frame->type != FRAME_TYPE_INTERP_TO_MANAGED && *lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) {
620 /*
621 * Remove any unused lmf.
622 * Mask out the lower bits which might be used to hold additional information.
623 */
624 *lmf = (MonoLMF *)(((gsize)(*lmf)->previous_lmf) & ~(SIZEOF_VOID_P -1));
625 }
626
627 if (frame->ji && !frame->ji->is_trampoline && !frame->ji->async)
628 method = jinfo_get_method (frame->ji);
629
630 if (frame->type == FRAME_TYPE_MANAGED && method) {
631 if (!method->wrapper_type || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
632 frame->managed = TRUE;
633 }
634
635 if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) {
636 /*
637 * This type of frame is just a marker, the caller should unwind once more to get the
638 * last managed frame.
639 */
640 frame->ji = NULL;
641 frame->method = NULL;
642 }
643
644 frame->native_offset = -1;
645 frame->domain = target_domain;
646 frame->async_context = async;
647
648 ji = frame->ji;
649
650 if (frame->type == FRAME_TYPE_MANAGED)
651 frame->method = method;
652
653 if (ji && (frame->managed || (method && method->wrapper_type))) {
654 const char *real_ip, *start;
655
656 start = (const char *)ji->code_start;
657 if (frame->type == FRAME_TYPE_MANAGED)
658 real_ip = (const char*)ip;
659 else
660 /* ctx->ip points into native code */
661 real_ip = (const char*)MONO_CONTEXT_GET_IP (new_ctx);
662
663 if ((real_ip >= start) && (real_ip <= start + ji->code_size))
664 frame->native_offset = real_ip - start;
665 else {
666 frame->native_offset = -1;
667 }
668
669 if (trace)
670 *trace = mono_debug_print_stack_frame (method, frame->native_offset, domain);
671 } else {
672 if (trace && frame->method) {
673 char *fname = mono_method_full_name (frame->method, TRUE);
674 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
675 g_free (fname);
676 }
677 }
678
679 return TRUE;
680 }
681
682 typedef struct {
683 gboolean in_interp;
684 MonoInterpStackIter interp_iter;
685 } Unwinder;
686
687 static void
unwinder_init(Unwinder * unwinder)688 unwinder_init (Unwinder *unwinder)
689 {
690 memset (unwinder, 0, sizeof (Unwinder));
691 }
692
693 #if defined(__GNUC__) && defined(TARGET_ARM64)
694 /* gcc 4.9.2 seems to miscompile this on arm64 */
695 static __attribute__((optimize("O0"))) gboolean
696 #else
697 static gboolean
698 #endif
unwinder_unwind_frame(Unwinder * unwinder,MonoDomain * domain,MonoJitTlsData * jit_tls,MonoJitInfo * prev_ji,MonoContext * ctx,MonoContext * new_ctx,char ** trace,MonoLMF ** lmf,mgreg_t ** save_locations,StackFrameInfo * frame)699 unwinder_unwind_frame (Unwinder *unwinder,
700 MonoDomain *domain, MonoJitTlsData *jit_tls,
701 MonoJitInfo *prev_ji, MonoContext *ctx,
702 MonoContext *new_ctx, char **trace, MonoLMF **lmf,
703 mgreg_t **save_locations,
704 StackFrameInfo *frame)
705 {
706 if (unwinder->in_interp) {
707 gpointer parent;
708 memcpy (new_ctx, ctx, sizeof (MonoContext));
709
710 /* Process debugger invokes */
711 /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */
712 if ((gpointer)MONO_CONTEXT_GET_SP (ctx) > (gpointer)(*lmf)) {
713 if (((guint64)(*lmf)->previous_lmf) & 2) {
714 MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
715 if (ext->debugger_invoke) {
716 *lmf = (MonoLMF *)(((guint64)(*lmf)->previous_lmf) & ~7);
717 frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
718 return TRUE;
719 }
720 }
721 }
722
723 unwinder->in_interp = mini_get_interp_callbacks ()->frame_iter_next (&unwinder->interp_iter, frame);
724 if (frame->type == FRAME_TYPE_INTERP) {
725 parent = mini_get_interp_callbacks ()->frame_get_parent (frame->interp_frame);
726 /* This is needed so code which uses ctx->sp for frame ordering would work */
727 MONO_CONTEXT_SET_SP (new_ctx, parent);
728 }
729 if (!unwinder->in_interp)
730 return unwinder_unwind_frame (unwinder, domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, save_locations, frame);
731 return TRUE;
732 } else {
733 gboolean res = mono_find_jit_info_ext (domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf,
734 save_locations, frame);
735 if (!res)
736 return FALSE;
737 if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED) {
738 unwinder->in_interp = TRUE;
739 mini_get_interp_callbacks ()->frame_iter_init (&unwinder->interp_iter, frame->interp_exit_data);
740 }
741 return TRUE;
742 }
743 }
744
745 /*
746 * This function is async-safe.
747 */
748 static gpointer
get_generic_info_from_stack_frame(MonoJitInfo * ji,MonoContext * ctx)749 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
750 {
751 MonoGenericJitInfo *gi;
752 MonoMethod *method;
753 gpointer info;
754
755 if (!ji->has_generic_jit_info)
756 return NULL;
757 gi = mono_jit_info_get_generic_jit_info (ji);
758 if (!gi->has_this)
759 return NULL;
760
761 info = NULL;
762 /*
763 * Search location list if available, it contains the precise location of the
764 * argument for every pc offset, even if the method was interrupted while it was in
765 * its prolog.
766 */
767 if (gi->nlocs) {
768 int offset = (mgreg_t)MONO_CONTEXT_GET_IP (ctx) - (mgreg_t)ji->code_start;
769 int i;
770
771 for (i = 0; i < gi->nlocs; ++i) {
772 MonoDwarfLocListEntry *entry = &gi->locations [i];
773
774 if (offset >= entry->from && (offset < entry->to || entry->to == 0)) {
775 if (entry->is_reg)
776 info = (gpointer)mono_arch_context_get_int_reg (ctx, entry->reg);
777 else
778 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, entry->reg) + entry->offset);
779 break;
780 }
781 }
782 g_assert (i < gi->nlocs);
783 } else {
784 if (gi->this_in_reg)
785 info = (gpointer)mono_arch_context_get_int_reg (ctx, gi->this_reg);
786 else
787 info = *(gpointer*)(gpointer)((char*)mono_arch_context_get_int_reg (ctx, gi->this_reg) +
788 gi->this_offset);
789 }
790
791 method = jinfo_get_method (ji);
792 if (mono_method_get_context (method)->method_inst) {
793 /* A MonoMethodRuntimeGenericContext* */
794 return info;
795 } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype) {
796 /* A MonoVTable* */
797 return info;
798 } else {
799 /* Avoid returning a managed object */
800 MonoObject *this_obj = (MonoObject *)info;
801
802 return this_obj->vtable;
803 }
804 }
805
806 /*
807 * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
808 */
809 static MonoGenericContext
get_generic_context_from_stack_frame(MonoJitInfo * ji,gpointer generic_info)810 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
811 {
812 MonoGenericContext context = { NULL, NULL };
813 MonoClass *klass, *method_container_class;
814 MonoMethod *method;
815
816 g_assert (generic_info);
817
818 method = jinfo_get_method (ji);
819 g_assert (method->is_inflated);
820 if (mono_method_get_context (method)->method_inst) {
821 MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext *)generic_info;
822
823 klass = mrgctx->class_vtable->klass;
824 context.method_inst = mrgctx->method_inst;
825 g_assert (context.method_inst);
826 } else {
827 MonoVTable *vtable = (MonoVTable *)generic_info;
828
829 klass = vtable->klass;
830 }
831
832 //g_assert (!mono_class_is_gtd (method->klass));
833 if (mono_class_is_ginst (method->klass))
834 method_container_class = mono_class_get_generic_class (method->klass)->container_class;
835 else
836 method_container_class = method->klass;
837
838 /* class might refer to a subclass of method's class */
839 while (!(klass == method->klass || (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->container_class == method_container_class))) {
840 klass = klass->parent;
841 g_assert (klass);
842 }
843
844 if (mono_class_is_ginst (klass) || mono_class_is_gtd (klass))
845 context.class_inst = mini_class_get_context (klass)->class_inst;
846
847 if (mono_class_is_ginst (klass))
848 g_assert (mono_class_has_parent_and_ignore_generics (mono_class_get_generic_class (klass)->container_class, method_container_class));
849 else
850 g_assert (mono_class_has_parent_and_ignore_generics (klass, method_container_class));
851
852 return context;
853 }
854
855 static MonoMethod*
get_method_from_stack_frame(MonoJitInfo * ji,gpointer generic_info)856 get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
857 {
858 MonoError error;
859 MonoGenericContext context;
860 MonoMethod *method;
861
862 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
863 return jinfo_get_method (ji);
864 context = get_generic_context_from_stack_frame (ji, generic_info);
865
866 method = jinfo_get_method (ji);
867 method = mono_method_get_declaring_generic_method (method);
868 method = mono_class_inflate_generic_method_checked (method, &context, &error);
869 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
870
871 return method;
872 }
873
874 /**
875 * mono_exception_walk_native_trace:
876 * \param ex The exception object whose frames should be walked
877 * \param func callback to call for each stack frame
878 * \param user_data data passed to the callback
879 * This function walks the stacktrace of an exception. For
880 * each frame the callback function is called with the relevant info.
881 * The walk ends when no more stack frames are found or when the callback
882 * returns a TRUE value.
883 */
884
885 gboolean
mono_exception_walk_trace(MonoException * ex,MonoExceptionFrameWalk func,gpointer user_data)886 mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data)
887 {
888 MONO_REQ_GC_UNSAFE_MODE;
889
890 MonoDomain *domain = mono_domain_get ();
891 MonoArray *ta = ex->trace_ips;
892 int len, i;
893
894 if (ta == NULL)
895 return FALSE;
896
897 len = mono_array_length (ta) / TRACE_IP_ENTRY_SIZE;
898 for (i = 0; i < len; i++) {
899 ExceptionTraceIp trace_ip;
900
901 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
902 gpointer ip = trace_ip.ip;
903 gpointer generic_info = trace_ip.generic_info;
904 MonoJitInfo *ji = mono_jit_info_table_find (domain, (char *)ip);
905
906 if (ji == NULL) {
907 if (func (NULL, ip, 0, FALSE, user_data))
908 return TRUE;
909 } else {
910 MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
911 if (func (method, ji->code_start, (char *) ip - (char *) ji->code_start, TRUE, user_data))
912 return TRUE;
913 }
914 }
915
916 return len > 0;
917 }
918
919 MonoArray *
ves_icall_get_trace(MonoException * exc,gint32 skip,MonoBoolean need_file_info)920 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
921 {
922 MonoError error;
923 MonoDomain *domain = mono_domain_get ();
924 MonoArray *res;
925 MonoArray *ta = exc->trace_ips;
926 MonoDebugSourceLocation *location;
927 int i, len;
928
929 if (ta == NULL) {
930 /* Exception is not thrown yet */
931 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, &error);
932 mono_error_set_pending_exception (&error);
933 return res;
934 }
935
936 len = mono_array_length (ta) / TRACE_IP_ENTRY_SIZE;
937
938 res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, &error);
939 if (mono_error_set_pending_exception (&error))
940 return NULL;
941
942 for (i = skip; i < len; i++) {
943 MonoJitInfo *ji;
944 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, &error);
945 if (!mono_error_ok (&error)) {
946 mono_error_set_pending_exception (&error);
947 return NULL;
948 }
949 ExceptionTraceIp trace_ip;
950 memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp));
951 gpointer ip = trace_ip.ip;
952 gpointer generic_info = trace_ip.generic_info;
953 MonoMethod *method;
954
955 if (trace_ip.ji) {
956 ji = trace_ip.ji;
957 } else {
958 ji = mono_jit_info_table_find (domain, (char *)ip);
959 if (ji == NULL) {
960 /* Unmanaged frame */
961 mono_array_setref (res, i, sf);
962 continue;
963 }
964 }
965
966 g_assert (ji != NULL);
967
968 if (mono_llvm_only || !generic_info)
969 /* Can't resolve actual method */
970 method = jinfo_get_method (ji);
971 else
972 method = get_method_from_stack_frame (ji, generic_info);
973 if (jinfo_get_method (ji)->wrapper_type) {
974 char *s;
975
976 sf->method = NULL;
977 s = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_REFLECTION);
978 MonoString *name = mono_string_new_checked (domain, s, &error);
979 g_free (s);
980 if (!is_ok (&error)) {
981 mono_error_set_pending_exception (&error);
982 return NULL;
983 }
984 MONO_OBJECT_SETREF (sf, internal_method_name, name);
985 }
986 else {
987 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
988 if (!mono_error_ok (&error)) {
989 mono_error_set_pending_exception (&error);
990 return NULL;
991 }
992 MONO_OBJECT_SETREF (sf, method, rm);
993 }
994
995 sf->method_index = ji->from_aot ? mono_aot_find_method_index (method) : 0xffffff;
996 sf->method_address = (gsize) ji->code_start;
997 sf->native_offset = (char *)ip - (char *)ji->code_start;
998
999 /*
1000 * mono_debug_lookup_source_location() returns both the file / line number information
1001 * and the IL offset. Note that computing the IL offset is already an expensive
1002 * operation, so we shouldn't call this method twice.
1003 */
1004 location = mono_debug_lookup_source_location (jinfo_get_method (ji), sf->native_offset, domain);
1005 if (location) {
1006 sf->il_offset = location->il_offset;
1007 } else {
1008 SeqPoint sp;
1009 if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (ji), sf->native_offset, NULL, &sp))
1010 sf->il_offset = sp.il_offset;
1011 else
1012 sf->il_offset = -1;
1013 }
1014
1015 if (need_file_info) {
1016 if (location && location->source_file) {
1017 MonoString *filename = mono_string_new_checked (domain, location->source_file, &error);
1018 if (!is_ok (&error)) {
1019 mono_error_set_pending_exception (&error);
1020 return NULL;
1021 }
1022 MONO_OBJECT_SETREF (sf, filename, filename);
1023 sf->line = location->row;
1024 sf->column = location->column;
1025 } else {
1026 sf->line = sf->column = 0;
1027 sf->filename = NULL;
1028 }
1029 }
1030
1031 mono_debug_free_source_location (location);
1032 mono_array_setref (res, i, sf);
1033 }
1034
1035 return res;
1036 }
1037
1038 static void
mono_runtime_walk_stack_with_ctx(MonoJitStackWalk func,MonoContext * start_ctx,MonoUnwindOptions unwind_options,void * user_data)1039 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1040 {
1041 if (!start_ctx) {
1042 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1043 if (jit_tls && jit_tls->orig_ex_ctx_set)
1044 start_ctx = &jit_tls->orig_ex_ctx;
1045 }
1046 mono_walk_stack_with_ctx (func, start_ctx, unwind_options, user_data);
1047 }
1048 /**
1049 * mono_walk_stack_with_ctx:
1050 * Unwind the current thread starting at \p start_ctx.
1051 * If \p start_ctx is null, we capture the current context.
1052 */
1053 void
mono_walk_stack_with_ctx(MonoJitStackWalk func,MonoContext * start_ctx,MonoUnwindOptions unwind_options,void * user_data)1054 mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
1055 {
1056 MonoContext extra_ctx;
1057 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
1058 MONO_ARCH_CONTEXT_DEF
1059
1060 if (!thread || !thread->jit_data)
1061 return;
1062
1063 if (!start_ctx) {
1064 mono_arch_flush_register_windows ();
1065
1066 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1067 MONO_INIT_CONTEXT_FROM_CURRENT (&extra_ctx);
1068 #else
1069 MONO_INIT_CONTEXT_FROM_FUNC (&extra_ctx, mono_walk_stack_with_ctx);
1070 #endif
1071 start_ctx = &extra_ctx;
1072 }
1073
1074 mono_walk_stack_full (func, start_ctx, mono_domain_get (), (MonoJitTlsData *)thread->jit_data, mono_get_lmf (), unwind_options, user_data);
1075 }
1076
1077 /**
1078 * mono_walk_stack_with_state:
1079 * Unwind a thread described by \p state.
1080 *
1081 * State must be valid (state->valid == TRUE).
1082 *
1083 * If you are using this function to unwind another thread, make sure it is suspended.
1084 *
1085 * If \p state is null, we capture the current context.
1086 */
1087 void
mono_walk_stack_with_state(MonoJitStackWalk func,MonoThreadUnwindState * state,MonoUnwindOptions unwind_options,void * user_data)1088 mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data)
1089 {
1090 MonoThreadUnwindState extra_state;
1091 if (!state) {
1092 g_assert (!mono_thread_info_is_async_context ());
1093 if (!mono_thread_state_init_from_current (&extra_state))
1094 return;
1095 state = &extra_state;
1096 }
1097
1098 g_assert (state->valid);
1099
1100 if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
1101 /* Not attached */
1102 return;
1103
1104 mono_walk_stack_full (func,
1105 &state->ctx,
1106 (MonoDomain *)state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
1107 (MonoJitTlsData *)state->unwind_data [MONO_UNWIND_DATA_JIT_TLS],
1108 (MonoLMF *)state->unwind_data [MONO_UNWIND_DATA_LMF],
1109 unwind_options, user_data);
1110 }
1111
1112 void
mono_walk_stack(MonoJitStackWalk func,MonoUnwindOptions options,void * user_data)1113 mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_data)
1114 {
1115 MonoThreadUnwindState state;
1116 if (!mono_thread_state_init_from_current (&state))
1117 return;
1118 mono_walk_stack_with_state (func, &state, options, user_data);
1119 }
1120
1121 /**
1122 * mono_walk_stack_full:
1123 * \param func callback to call for each stack frame
1124 * \param domain starting appdomain, can be NULL to use the current domain
1125 * \param unwind_options what extra information the unwinder should gather
1126 * \param start_ctx starting state of the stack walk, can be NULL.
1127 * \param thread the thread whose stack to walk, can be NULL to use the current thread
1128 * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread
1129 * \param user_data data passed to the callback
1130 * This function walks the stack of a thread, starting from the state
1131 * represented by \p start_ctx. For each frame the callback
1132 * function is called with the relevant info. The walk ends when no more
1133 * managed stack frames are found or when the callback returns a TRUE value.
1134 */
1135 static void
mono_walk_stack_full(MonoJitStackWalk func,MonoContext * start_ctx,MonoDomain * domain,MonoJitTlsData * jit_tls,MonoLMF * lmf,MonoUnwindOptions unwind_options,gpointer user_data)1136 mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain *domain, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data)
1137 {
1138 gint il_offset, i;
1139 MonoContext ctx, new_ctx;
1140 StackFrameInfo frame;
1141 gboolean res;
1142 mgreg_t *reg_locations [MONO_MAX_IREGS];
1143 mgreg_t *new_reg_locations [MONO_MAX_IREGS];
1144 gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
1145 gboolean async = mono_thread_info_is_async_context ();
1146 Unwinder unwinder;
1147
1148 if (mono_llvm_only) {
1149 GSList *l, *ips;
1150
1151 if (async)
1152 return;
1153
1154 ips = get_unwind_backtrace ();
1155 for (l = ips; l; l = l->next) {
1156 guint8 *ip = (guint8*)l->data;
1157 memset (&frame, 0, sizeof (StackFrameInfo));
1158 frame.ji = mini_jit_info_table_find (domain, (char*)ip, &frame.domain);
1159 if (!frame.ji || frame.ji->is_trampoline)
1160 continue;
1161 frame.type = FRAME_TYPE_MANAGED;
1162 frame.method = jinfo_get_method (frame.ji);
1163 // FIXME: Cannot lookup the actual method
1164 frame.actual_method = frame.method;
1165 if (frame.type == FRAME_TYPE_MANAGED) {
1166 if (!frame.method->wrapper_type || frame.method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
1167 frame.managed = TRUE;
1168 }
1169 frame.native_offset = ip - (guint8*)frame.ji->code_start;
1170 frame.il_offset = -1;
1171
1172 if (func (&frame, NULL, user_data))
1173 break;
1174 }
1175 g_free (ips);
1176 return;
1177 }
1178
1179 g_assert (start_ctx);
1180 g_assert (domain);
1181 g_assert (jit_tls);
1182 /*The LMF will be null if the target have no managed frames.*/
1183 /* g_assert (lmf); */
1184
1185 if (async)
1186 g_assert (unwind_options == MONO_UNWIND_NONE);
1187
1188 memcpy (&ctx, start_ctx, sizeof (MonoContext));
1189 memset (reg_locations, 0, sizeof (reg_locations));
1190
1191 unwinder_init (&unwinder);
1192
1193 while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
1194 frame.lmf = lmf;
1195 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
1196 if (!res)
1197 return;
1198
1199 if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji && !frame.ji->is_trampoline) {
1200 MonoDebugSourceLocation *source;
1201
1202 source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain);
1203 if (source) {
1204 il_offset = source->il_offset;
1205 } else {
1206 SeqPoint sp;
1207 if (mono_find_prev_seq_point_for_native_offset (domain, jinfo_get_method (frame.ji), frame.native_offset, NULL, &sp))
1208 il_offset = sp.il_offset;
1209 else
1210 il_offset = -1;
1211 }
1212 mono_debug_free_source_location (source);
1213 } else
1214 il_offset = -1;
1215
1216 frame.il_offset = il_offset;
1217
1218 if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji && !frame.ji->is_trampoline) {
1219 frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
1220 } else {
1221 frame.actual_method = frame.method;
1222 }
1223
1224 if (get_reg_locations)
1225 frame.reg_locations = reg_locations;
1226
1227 if (func (&frame, &ctx, user_data))
1228 return;
1229
1230 if (get_reg_locations) {
1231 for (i = 0; i < MONO_MAX_IREGS; ++i)
1232 if (new_reg_locations [i])
1233 reg_locations [i] = new_reg_locations [i];
1234 }
1235
1236 ctx = new_ctx;
1237 }
1238 }
1239
1240 MonoBoolean
ves_icall_get_frame_info(gint32 skip,MonoBoolean need_file_info,MonoReflectionMethod ** method,gint32 * iloffset,gint32 * native_offset,MonoString ** file,gint32 * line,gint32 * column)1241 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
1242 MonoReflectionMethod **method,
1243 gint32 *iloffset, gint32 *native_offset,
1244 MonoString **file, gint32 *line, gint32 *column)
1245 {
1246 MonoError error;
1247 MonoDomain *domain = mono_domain_get ();
1248 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1249 MonoLMF *lmf = mono_get_lmf ();
1250 MonoJitInfo *ji = NULL;
1251 MonoContext ctx, new_ctx;
1252 MonoDebugSourceLocation *location;
1253 MonoMethod *jmethod = NULL, *actual_method;
1254 StackFrameInfo frame;
1255 gboolean res;
1256 Unwinder unwinder;
1257 int il_offset = -1;
1258
1259 MONO_ARCH_CONTEXT_DEF;
1260
1261 if (mono_llvm_only) {
1262 GSList *l, *ips;
1263 MonoDomain *frame_domain;
1264 guint8 *frame_ip = NULL;
1265
1266 /* FIXME: Generalize this code with an interface which returns an array of StackFrame structures */
1267 jmethod = NULL;
1268 ips = get_unwind_backtrace ();
1269 for (l = ips; l && skip >= 0; l = l->next) {
1270 guint8 *ip = (guint8*)l->data;
1271
1272 frame_ip = ip;
1273
1274 ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &frame_domain);
1275 if (!ji || ji->is_trampoline)
1276 continue;
1277
1278 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1279 jmethod = jinfo_get_method (ji);
1280 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1281 continue;
1282 skip--;
1283 }
1284 g_slist_free (ips);
1285 if (!jmethod || !l)
1286 return FALSE;
1287 /* No way to resolve generic instances */
1288 actual_method = jmethod;
1289 *native_offset = frame_ip - (guint8*)ji->code_start;
1290 } else {
1291 mono_arch_flush_register_windows ();
1292
1293 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1294 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx);
1295 #else
1296 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info);
1297 #endif
1298
1299 unwinder_init (&unwinder);
1300
1301 new_ctx = ctx;
1302 do {
1303 ctx = new_ctx;
1304 res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1305 if (!res)
1306 return FALSE;
1307 switch (frame.type) {
1308 case FRAME_TYPE_MANAGED_TO_NATIVE:
1309 case FRAME_TYPE_DEBUGGER_INVOKE:
1310 case FRAME_TYPE_TRAMPOLINE:
1311 case FRAME_TYPE_INTERP_TO_MANAGED:
1312 continue;
1313 case FRAME_TYPE_INTERP:
1314 skip--;
1315 break;
1316 default:
1317 ji = frame.ji;
1318 *native_offset = frame.native_offset;
1319
1320 /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */
1321 jmethod = jinfo_get_method (ji);
1322 if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)
1323 continue;
1324 skip--;
1325 break;
1326 }
1327 } while (skip >= 0);
1328
1329 if (frame.type == FRAME_TYPE_INTERP) {
1330 jmethod = frame.method;
1331 actual_method = frame.actual_method;
1332 *native_offset = frame.native_offset;
1333 } else {
1334 actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx));
1335 }
1336 }
1337
1338 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, actual_method, NULL, &error);
1339 if (!mono_error_ok (&error)) {
1340 mono_error_set_pending_exception (&error);
1341 return FALSE;
1342 }
1343 mono_gc_wbarrier_generic_store (method, (MonoObject*) rm);
1344
1345 if (il_offset != -1) {
1346 location = mono_debug_lookup_source_location_by_il (jmethod, il_offset, domain);
1347 } else {
1348 location = mono_debug_lookup_source_location (jmethod, *native_offset, domain);
1349 }
1350 if (location)
1351 *iloffset = location->il_offset;
1352 else
1353 *iloffset = 0;
1354
1355 if (need_file_info) {
1356 if (location) {
1357 MonoString *filename = mono_string_new_checked (domain, location->source_file, &error);
1358 if (!is_ok (&error)) {
1359 mono_error_set_pending_exception (&error);
1360 return FALSE;
1361 }
1362 mono_gc_wbarrier_generic_store (file, (MonoObject*)filename);
1363 *line = location->row;
1364 *column = location->column;
1365 } else {
1366 *file = NULL;
1367 *line = *column = 0;
1368 }
1369 }
1370
1371 mono_debug_free_source_location (location);
1372
1373 return TRUE;
1374 }
1375
1376 static MonoClass*
get_exception_catch_class(MonoJitExceptionInfo * ei,MonoJitInfo * ji,MonoContext * ctx)1377 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
1378 {
1379 MonoError error;
1380 MonoClass *catch_class = ei->data.catch_class;
1381 MonoType *inflated_type;
1382 MonoGenericContext context;
1383
1384 /*MonoJitExceptionInfo::data is an union used by filter and finally clauses too.*/
1385 if (!catch_class || ei->flags != MONO_EXCEPTION_CLAUSE_NONE)
1386 return NULL;
1387
1388 if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
1389 return catch_class;
1390 context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
1391
1392 /* FIXME: we shouldn't inflate but instead put the
1393 type in the rgctx and fetch it from there. It
1394 might be a good idea to do this lazily, i.e. only
1395 when the exception is actually thrown, so as not to
1396 waste space for exception clauses which might never
1397 be encountered. */
1398 inflated_type = mono_class_inflate_generic_type_checked (&catch_class->byval_arg, &context, &error);
1399 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1400
1401 catch_class = mono_class_from_mono_type (inflated_type);
1402 mono_metadata_free_type (inflated_type);
1403
1404 return catch_class;
1405 }
1406
1407 /*
1408 * mini_jit_info_table_find_ext:
1409 *
1410 * Same as mono_jit_info_table_find, but search all the domains of the current thread
1411 * if ADDR is not found in DOMAIN. The domain where the method was found is stored into
1412 * OUT_DOMAIN if it is not NULL.
1413 */
1414 MonoJitInfo*
mini_jit_info_table_find_ext(MonoDomain * domain,char * addr,gboolean allow_trampolines,MonoDomain ** out_domain)1415 mini_jit_info_table_find_ext (MonoDomain *domain, char *addr, gboolean allow_trampolines, MonoDomain **out_domain)
1416 {
1417 MonoJitInfo *ji;
1418 MonoInternalThread *t = mono_thread_internal_current ();
1419 gpointer *refs;
1420
1421 if (out_domain)
1422 *out_domain = NULL;
1423
1424 ji = mono_jit_info_table_find_internal (domain, addr, TRUE, allow_trampolines);
1425 if (ji) {
1426 if (out_domain)
1427 *out_domain = domain;
1428 return ji;
1429 }
1430
1431 /* maybe it is shared code, so we also search in the root domain */
1432 if (domain != mono_get_root_domain ()) {
1433 ji = mono_jit_info_table_find_internal (mono_get_root_domain (), addr, TRUE, allow_trampolines);
1434 if (ji) {
1435 if (out_domain)
1436 *out_domain = mono_get_root_domain ();
1437 return ji;
1438 }
1439 }
1440
1441 if (!t)
1442 return NULL;
1443
1444 refs = (gpointer *)((t->appdomain_refs) ? *(gpointer *) t->appdomain_refs : NULL);
1445 for (; refs && *refs; refs++) {
1446 if (*refs != domain && *refs != mono_get_root_domain ()) {
1447 ji = mono_jit_info_table_find_internal ((MonoDomain*) *refs, addr, TRUE, allow_trampolines);
1448 if (ji) {
1449 if (out_domain)
1450 *out_domain = (MonoDomain*) *refs;
1451 return ji;
1452 }
1453 }
1454 }
1455
1456 return NULL;
1457 }
1458
1459 MonoJitInfo*
mini_jit_info_table_find(MonoDomain * domain,char * addr,MonoDomain ** out_domain)1460 mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domain)
1461 {
1462 return mini_jit_info_table_find_ext (domain, addr, FALSE, out_domain);
1463 }
1464
1465 /* Class lazy loading functions */
1466 static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
1467
1468 /*
1469 * wrap_non_exception_throws:
1470 *
1471 * Determine whenever M's assembly has a RuntimeCompatibilityAttribute with the
1472 * WrapNonExceptionThrows flag set.
1473 */
1474 static gboolean
wrap_non_exception_throws(MonoMethod * m)1475 wrap_non_exception_throws (MonoMethod *m)
1476 {
1477 MonoError error;
1478 MonoAssembly *ass = m->klass->image->assembly;
1479 MonoCustomAttrInfo* attrs;
1480 MonoClass *klass;
1481 int i;
1482 gboolean val = FALSE;
1483
1484 if (m->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
1485 MonoDynamicMethod *dm = (MonoDynamicMethod *)m;
1486 if (dm->assembly)
1487 ass = dm->assembly;
1488 }
1489 g_assert (ass);
1490 if (ass->wrap_non_exception_throws_inited)
1491 return ass->wrap_non_exception_throws;
1492
1493 klass = mono_class_get_runtime_compat_attr_class ();
1494
1495 attrs = mono_custom_attrs_from_assembly_checked (ass, FALSE, &error);
1496 mono_error_cleanup (&error); /* FIXME don't swallow the error */
1497 if (attrs) {
1498 for (i = 0; i < attrs->num_attrs; ++i) {
1499 MonoCustomAttrEntry *attr = &attrs->attrs [i];
1500 const gchar *p;
1501 int num_named, named_type, name_len;
1502 char *name;
1503
1504 if (!attr->ctor || attr->ctor->klass != klass)
1505 continue;
1506 /* Decode the RuntimeCompatibilityAttribute. See reflection.c */
1507 p = (const char*)attr->data;
1508 g_assert (read16 (p) == 0x0001);
1509 p += 2;
1510 num_named = read16 (p);
1511 if (num_named != 1)
1512 continue;
1513 p += 2;
1514 named_type = *p;
1515 p ++;
1516 /* data_type = *p; */
1517 p ++;
1518 /* Property */
1519 if (named_type != 0x54)
1520 continue;
1521 name_len = mono_metadata_decode_blob_size (p, &p);
1522 name = (char *)g_malloc (name_len + 1);
1523 memcpy (name, p, name_len);
1524 name [name_len] = 0;
1525 p += name_len;
1526 g_assert (!strcmp (name, "WrapNonExceptionThrows"));
1527 g_free (name);
1528 /* The value is a BOOLEAN */
1529 val = *p;
1530 }
1531 mono_custom_attrs_free (attrs);
1532 }
1533
1534 ass->wrap_non_exception_throws = val;
1535 mono_memory_barrier ();
1536 ass->wrap_non_exception_throws_inited = TRUE;
1537
1538 return val;
1539 }
1540
1541 #define MAX_UNMANAGED_BACKTRACE 128
1542 static MonoArray*
build_native_trace(MonoError * error)1543 build_native_trace (MonoError *error)
1544 {
1545 error_init (error);
1546 /* This puppy only makes sense on mobile, IOW, ARM. */
1547 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
1548 MonoArray *res;
1549 void *native_trace [MAX_UNMANAGED_BACKTRACE];
1550 int size = -1;
1551 MONO_ENTER_GC_SAFE;
1552 size = backtrace (native_trace, MAX_UNMANAGED_BACKTRACE);
1553 MONO_EXIT_GC_SAFE;
1554 int i;
1555
1556 if (!size)
1557 return NULL;
1558 res = mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, size, error);
1559 return_val_if_nok (error, NULL);
1560
1561 for (i = 0; i < size; i++)
1562 mono_array_set (res, gpointer, i, native_trace [i]);
1563 return res;
1564 #else
1565 return NULL;
1566 #endif
1567 }
1568
1569 static void
setup_stack_trace(MonoException * mono_ex,GSList * dynamic_methods,GList ** trace_ips)1570 setup_stack_trace (MonoException *mono_ex, GSList *dynamic_methods, GList **trace_ips)
1571 {
1572 if (mono_ex) {
1573 *trace_ips = g_list_reverse (*trace_ips);
1574 MonoError error;
1575 MonoArray *ips_arr = mono_glist_to_array (*trace_ips, mono_defaults.int_class, &error);
1576 mono_error_assert_ok (&error);
1577 MONO_OBJECT_SETREF (mono_ex, trace_ips, ips_arr);
1578 MONO_OBJECT_SETREF (mono_ex, native_trace_ips, build_native_trace (&error));
1579 mono_error_assert_ok (&error);
1580 if (dynamic_methods) {
1581 /* These methods could go away anytime, so save a reference to them in the exception object */
1582 GSList *l;
1583 MonoMList *list = NULL;
1584
1585 for (l = dynamic_methods; l; l = l->next) {
1586 guint32 dis_link;
1587 MonoDomain *domain = mono_domain_get ();
1588
1589 if (domain->method_to_dyn_method) {
1590 mono_domain_lock (domain);
1591 dis_link = (guint32)(size_t)g_hash_table_lookup (domain->method_to_dyn_method, l->data);
1592 mono_domain_unlock (domain);
1593 if (dis_link) {
1594 MonoObject *o = mono_gchandle_get_target (dis_link);
1595 if (o) {
1596 list = mono_mlist_prepend_checked (list, o, &error);
1597 mono_error_assert_ok (&error);
1598 }
1599 }
1600 }
1601 }
1602
1603 MONO_OBJECT_SETREF (mono_ex, dynamic_methods, list);
1604 }
1605 }
1606 g_list_free (*trace_ips);
1607 *trace_ips = NULL;
1608 }
1609
1610 /*
1611 * handle_exception_first_pass:
1612 *
1613 * The first pass of exception handling. Unwind the stack until a catch clause which can catch
1614 * OBJ is found. Store the index of the filter clause which caught the exception into
1615 * OUT_FILTER_IDX. Return TRUE if the exception is caught, FALSE otherwise.
1616 */
1617 static gboolean
handle_exception_first_pass(MonoContext * ctx,MonoObject * obj,gint32 * out_filter_idx,MonoJitInfo ** out_ji,MonoJitInfo ** out_prev_ji,MonoObject * non_exception,StackFrameInfo * catch_frame)1618 handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception, StackFrameInfo *catch_frame)
1619 {
1620 MonoError error;
1621 MonoDomain *domain = mono_domain_get ();
1622 MonoJitInfo *ji = NULL;
1623 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1624 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1625 MonoLMF *lmf = mono_get_lmf ();
1626 GList *trace_ips = NULL;
1627 GSList *dynamic_methods = NULL;
1628 MonoException *mono_ex;
1629 gboolean stack_overflow = FALSE;
1630 MonoContext initial_ctx;
1631 MonoMethod *method;
1632 int frame_count = 0;
1633 gint32 filter_idx;
1634 int i;
1635 MonoObject *ex_obj;
1636 Unwinder unwinder;
1637 gboolean in_interp;
1638
1639 g_assert (ctx != NULL);
1640
1641 if (obj == (MonoObject *)domain->stack_overflow_ex)
1642 stack_overflow = TRUE;
1643
1644 mono_ex = (MonoException*)obj;
1645 MonoArray *initial_trace_ips = mono_ex->trace_ips;
1646 if (initial_trace_ips) {
1647 int len = mono_array_length (initial_trace_ips) / TRACE_IP_ENTRY_SIZE;
1648
1649 for (i = 0; i < (len - 1); i++) {
1650 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
1651 gpointer p = mono_array_get (initial_trace_ips, gpointer, (i * TRACE_IP_ENTRY_SIZE) + j);
1652 trace_ips = g_list_prepend (trace_ips, p);
1653 }
1654 }
1655 }
1656
1657 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, &error)) {
1658 mono_error_assert_ok (&error);
1659 mono_ex = NULL;
1660 }
1661
1662 if (!call_filter)
1663 call_filter = (int (*) (MonoContext *, void *))mono_get_call_filter ();
1664
1665 g_assert (jit_tls->end_of_stack);
1666 g_assert (jit_tls->abort_func);
1667
1668 if (out_filter_idx)
1669 *out_filter_idx = -1;
1670 if (out_ji)
1671 *out_ji = NULL;
1672 if (out_prev_ji)
1673 *out_prev_ji = NULL;
1674 filter_idx = 0;
1675 initial_ctx = *ctx;
1676
1677 unwinder_init (&unwinder);
1678
1679 while (1) {
1680 MonoContext new_ctx;
1681 guint32 free_stack;
1682 int clause_index_start = 0;
1683 gboolean unwind_res = TRUE;
1684
1685 StackFrameInfo frame;
1686
1687 if (out_prev_ji)
1688 *out_prev_ji = ji;
1689
1690 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
1691 if (!unwind_res) {
1692 setup_stack_trace (mono_ex, dynamic_methods, &trace_ips);
1693 g_slist_free (dynamic_methods);
1694 return FALSE;
1695 }
1696
1697 switch (frame.type) {
1698 case FRAME_TYPE_DEBUGGER_INVOKE:
1699 case FRAME_TYPE_MANAGED_TO_NATIVE:
1700 case FRAME_TYPE_TRAMPOLINE:
1701 case FRAME_TYPE_INTERP_TO_MANAGED:
1702 *ctx = new_ctx;
1703 continue;
1704 case FRAME_TYPE_INTERP:
1705 case FRAME_TYPE_MANAGED:
1706 break;
1707 default:
1708 g_assert_not_reached ();
1709 break;
1710 }
1711
1712 in_interp = frame.type == FRAME_TYPE_INTERP;
1713 ji = frame.ji;
1714
1715 gpointer ip;
1716 if (in_interp)
1717 ip = (guint8*)ji->code_start + frame.native_offset;
1718 else
1719 ip = MONO_CONTEXT_GET_IP (ctx);
1720
1721 frame_count ++;
1722 method = jinfo_get_method (ji);
1723 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
1724
1725 if (mini_get_debug_options ()->reverse_pinvoke_exceptions && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
1726 g_error ("A native frame was found while unwinding the stack after an exception.\n"
1727 "The native frame called the managed method:\n%s\n",
1728 mono_method_full_name (method, TRUE));
1729 }
1730
1731 if (method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1732 // avoid giant stack traces during a stack overflow
1733 if (frame_count < 1000) {
1734 trace_ips = g_list_prepend (trace_ips, ip);
1735 trace_ips = g_list_prepend (trace_ips, get_generic_info_from_stack_frame (ji, ctx));
1736 trace_ips = g_list_prepend (trace_ips, ji);
1737 }
1738 }
1739
1740 if (method->dynamic)
1741 dynamic_methods = g_slist_prepend (dynamic_methods, method);
1742
1743 if (stack_overflow) {
1744 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
1745 } else {
1746 free_stack = 0xffffff;
1747 }
1748
1749 for (i = clause_index_start; i < ji->num_clauses; i++) {
1750 MonoJitExceptionInfo *ei = &ji->clauses [i];
1751 gboolean filtered = FALSE;
1752
1753 /*
1754 * During stack overflow, wait till the unwinding frees some stack
1755 * space before running handlers/finalizers.
1756 */
1757 if (free_stack <= (64 * 1024))
1758 continue;
1759
1760 if (is_address_protected (ji, ei, ip)) {
1761 /* catch block */
1762 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
1763
1764 /*
1765 * Have to unwrap RuntimeWrappedExceptions if the
1766 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
1767 */
1768 if (non_exception && !wrap_non_exception_throws (method))
1769 ex_obj = non_exception;
1770 else
1771 ex_obj = obj;
1772
1773 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
1774 #ifndef DISABLE_PERFCOUNTERS
1775 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_filters);
1776 #endif
1777
1778 if (!ji->is_interp) {
1779 #ifndef MONO_CROSS_COMPILE
1780 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
1781 if (ji->from_llvm)
1782 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
1783 else
1784 /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */
1785 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1786 #else
1787 g_assert (!ji->from_llvm);
1788 /* store the exception object in bp + ei->exvar_offset */
1789 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
1790 #endif
1791 #endif
1792
1793 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
1794 /*
1795 * Pass the original il clause index to the landing pad so it can
1796 * branch to the landing pad associated with the il clause.
1797 * This is needed because llvm compiled code assumes that the EH
1798 * code always branches to the innermost landing pad.
1799 */
1800 if (ji->from_llvm)
1801 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
1802 #endif
1803 }
1804
1805 mono_debugger_agent_begin_exception_filter (mono_ex, ctx, &initial_ctx);
1806 if (ji->is_interp) {
1807 filtered = mini_get_interp_callbacks ()->run_filter (&frame, (MonoException*)ex_obj, i, ei->data.filter);
1808 } else {
1809 filtered = call_filter (ctx, ei->data.filter);
1810 }
1811 mono_debugger_agent_end_exception_filter (mono_ex, ctx, &initial_ctx);
1812 if (filtered && out_filter_idx)
1813 *out_filter_idx = filter_idx;
1814 if (out_ji)
1815 *out_ji = ji;
1816 filter_idx ++;
1817
1818 if (filtered) {
1819 setup_stack_trace (mono_ex, dynamic_methods, &trace_ips);
1820 g_slist_free (dynamic_methods);
1821 /* mono_debugger_agent_handle_exception () needs this */
1822 mini_set_abort_threshold (ctx);
1823 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1824 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
1825 *catch_frame = frame;
1826 return TRUE;
1827 }
1828 }
1829
1830 MonoError isinst_error;
1831 error_init (&isinst_error);
1832 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, &error)) {
1833 setup_stack_trace (mono_ex, dynamic_methods, &trace_ips);
1834 g_slist_free (dynamic_methods);
1835
1836 if (out_ji)
1837 *out_ji = ji;
1838
1839 /* mono_debugger_agent_handle_exception () needs this */
1840 if (!in_interp)
1841 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1842 frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
1843 *catch_frame = frame;
1844 return TRUE;
1845 }
1846 mono_error_cleanup (&isinst_error);
1847 }
1848 }
1849
1850 *ctx = new_ctx;
1851 }
1852
1853 g_assert_not_reached ();
1854 }
1855
1856 /**
1857 * mono_handle_exception_internal:
1858 * \param ctx saved processor state
1859 * \param obj the exception object
1860 * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData.
1861 */
1862 static gboolean
mono_handle_exception_internal(MonoContext * ctx,MonoObject * obj,gboolean resume,MonoJitInfo ** out_ji)1863 mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resume, MonoJitInfo **out_ji)
1864 {
1865 MonoError error;
1866 MonoDomain *domain = mono_domain_get ();
1867 MonoJitInfo *ji, *prev_ji;
1868 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1869 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1870 MonoLMF *lmf = mono_get_lmf ();
1871 MonoException *mono_ex;
1872 gboolean stack_overflow = FALSE;
1873 MonoContext initial_ctx;
1874 MonoMethod *method;
1875 int frame_count = 0;
1876 gint32 filter_idx, first_filter_idx = 0;
1877 int i;
1878 MonoObject *ex_obj;
1879 MonoObject *non_exception = NULL;
1880 Unwinder unwinder;
1881 gboolean in_interp;
1882
1883 g_assert (ctx != NULL);
1884 if (!obj) {
1885 MonoException *ex = mono_get_exception_null_reference ();
1886 MonoString *msg = mono_string_new_checked (domain, "Object reference not set to an instance of an object", &error);
1887 mono_error_assert_ok (&error);
1888 MONO_OBJECT_SETREF (ex, message, msg);
1889 obj = (MonoObject *)ex;
1890 }
1891
1892 /*
1893 * Allocate a new exception object instead of the preconstructed ones.
1894 */
1895 if (obj == (MonoObject *)domain->stack_overflow_ex) {
1896 /*
1897 * It is not a good idea to try and put even more pressure on the little stack available.
1898 * obj = mono_get_exception_stack_overflow ();
1899 */
1900 stack_overflow = TRUE;
1901 }
1902 else if (obj == (MonoObject *)domain->null_reference_ex) {
1903 obj = (MonoObject *)mono_get_exception_null_reference ();
1904 }
1905
1906 if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, &error)) {
1907 mono_error_assert_ok (&error);
1908 non_exception = obj;
1909 obj = (MonoObject *)mono_get_exception_runtime_wrapped_checked (obj, &error);
1910 mono_error_assert_ok (&error);
1911 }
1912
1913 mono_ex = (MonoException*)obj;
1914
1915 if (mini_get_debug_options ()->suspend_on_exception) {
1916 mono_runtime_printf_err ("Exception thrown, suspending...");
1917 while (1)
1918 ;
1919 }
1920
1921 if (mono_object_isinst_checked (obj, mono_defaults.exception_class, &error)) {
1922 mono_ex = (MonoException*)obj;
1923 } else {
1924 mono_error_assert_ok (&error);
1925 mono_ex = NULL;
1926 }
1927
1928 if (mono_ex && jit_tls->class_cast_from) {
1929 if (!strcmp (mono_ex->object.vtable->klass->name, "InvalidCastException")) {
1930 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1931 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1932 char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name);
1933 mono_ex->message = mono_string_new_checked (domain, msg, &error);
1934 g_free (from_name);
1935 g_free (to_name);
1936 if (!is_ok (&error)) {
1937 mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg);
1938 mono_error_assert_ok (&error);
1939 }
1940 g_free (msg);
1941 }
1942 if (!strcmp (mono_ex->object.vtable->klass->name, "ArrayTypeMismatchException")) {
1943 char *from_name = mono_type_get_full_name (jit_tls->class_cast_from);
1944 char *to_name = mono_type_get_full_name (jit_tls->class_cast_to);
1945 char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name);
1946 mono_ex->message = mono_string_new_checked (domain, msg, &error);
1947 g_free (from_name);
1948 g_free (to_name);
1949 if (!is_ok (&error)) {
1950 mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg);
1951 mono_error_assert_ok (&error);
1952 }
1953 g_free (msg);
1954 }
1955 }
1956
1957 if (!call_filter)
1958 call_filter = (int (*)(MonoContext *, void*))mono_get_call_filter ();
1959
1960 g_assert (jit_tls->end_of_stack);
1961 g_assert (jit_tls->abort_func);
1962
1963 /*
1964 * We set orig_ex_ctx_set to TRUE/FALSE around profiler calls to make sure it doesn't
1965 * end up being TRUE on any code path.
1966 */
1967 memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
1968
1969 if (!resume) {
1970 gboolean res;
1971
1972 MonoContext ctx_cp = *ctx;
1973 if (mono_trace_is_enabled ()) {
1974 MonoMethod *system_exception_get_message = mono_class_get_method_from_name (mono_defaults.exception_class, "get_Message", 0);
1975 MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method (obj, system_exception_get_message);
1976 MonoObject *message;
1977 const char *type_name = mono_class_get_name (mono_object_class (mono_ex));
1978 char *msg = NULL;
1979 if (get_message == NULL) {
1980 message = NULL;
1981 } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
1982 message = NULL;
1983 msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
1984 } else {
1985 MonoObject *exc = NULL;
1986 message = mono_runtime_try_invoke (get_message, obj, NULL, &exc, &error);
1987 g_assert (exc == NULL);
1988 mono_error_assert_ok (&error);
1989 }
1990 if (msg == NULL) {
1991 if (message) {
1992 msg = mono_string_to_utf8_checked ((MonoString *) message, &error);
1993 if (!is_ok (&error)) {
1994 mono_error_cleanup (&error);
1995 msg = g_strdup ("(error while display System.Exception.Message property)");
1996 }
1997 } else {
1998 msg = g_strdup ("(System.Exception.Message property not available)");
1999 }
2000 }
2001 g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)mono_native_thread_id_get (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg);
2002 g_free (msg);
2003 if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
2004 mono_print_thread_dump_from_ctx (ctx);
2005 }
2006 jit_tls->orig_ex_ctx_set = TRUE;
2007 MONO_PROFILER_RAISE (exception_throw, (obj));
2008 jit_tls->orig_ex_ctx_set = FALSE;
2009
2010 StackFrameInfo catch_frame;
2011 res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame);
2012
2013 if (!res) {
2014 if (mini_get_debug_options ()->break_on_exc)
2015 G_BREAKPOINT ();
2016 mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2017
2018 if (mini_get_debug_options ()->suspend_on_unhandled) {
2019 mono_runtime_printf_err ("Unhandled exception, suspending...");
2020 while (1)
2021 ;
2022 }
2023
2024 // FIXME: This runs managed code so it might cause another stack overflow when
2025 // we are handling a stack overflow
2026 mini_set_abort_threshold (ctx);
2027 mono_unhandled_exception (obj);
2028 } else {
2029 gboolean unhandled = FALSE;
2030
2031 /*
2032 * The exceptions caught by the mono_runtime_invoke_checked () calls
2033 * in the threadpool needs to be treated as unhandled (#669836).
2034 *
2035 * FIXME: The check below is hackish, but its hard to distinguish
2036 * these runtime invoke calls from others in the runtime.
2037 */
2038 if (ji && jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
2039 if (prev_ji && jinfo_get_method (prev_ji) == mono_defaults.threadpool_perform_wait_callback_method)
2040 unhandled = TRUE;
2041 }
2042
2043 if (unhandled)
2044 mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL, NULL);
2045 else
2046 mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
2047 }
2048 }
2049
2050 if (out_ji)
2051 *out_ji = NULL;
2052 filter_idx = 0;
2053 initial_ctx = *ctx;
2054
2055 unwinder_init (&unwinder);
2056
2057 while (1) {
2058 MonoContext new_ctx;
2059 guint32 free_stack;
2060 int clause_index_start = 0;
2061 gboolean unwind_res = TRUE;
2062 StackFrameInfo frame;
2063 gpointer ip;
2064
2065 if (resume) {
2066 resume = FALSE;
2067 ji = jit_tls->resume_state.ji;
2068 new_ctx = jit_tls->resume_state.new_ctx;
2069 clause_index_start = jit_tls->resume_state.clause_index;
2070 lmf = jit_tls->resume_state.lmf;
2071 first_filter_idx = jit_tls->resume_state.first_filter_idx;
2072 filter_idx = jit_tls->resume_state.filter_idx;
2073 in_interp = FALSE;
2074 } else {
2075 unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
2076 if (!unwind_res) {
2077 *(mono_get_lmf_addr ()) = lmf;
2078
2079 jit_tls->abort_func (obj);
2080 g_assert_not_reached ();
2081 }
2082 switch (frame.type) {
2083 case FRAME_TYPE_DEBUGGER_INVOKE:
2084 case FRAME_TYPE_MANAGED_TO_NATIVE:
2085 case FRAME_TYPE_TRAMPOLINE:
2086 *ctx = new_ctx;
2087 continue;
2088 case FRAME_TYPE_INTERP_TO_MANAGED:
2089 continue;
2090 case FRAME_TYPE_INTERP:
2091 case FRAME_TYPE_MANAGED:
2092 break;
2093 default:
2094 g_assert_not_reached ();
2095 break;
2096 }
2097 in_interp = frame.type == FRAME_TYPE_INTERP;
2098 ji = frame.ji;
2099 }
2100
2101 if (in_interp)
2102 ip = (guint8*)ji->code_start + frame.native_offset;
2103 else
2104 ip = MONO_CONTEXT_GET_IP (ctx);
2105
2106 method = jinfo_get_method (ji);
2107 frame_count ++;
2108 //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
2109
2110 if (stack_overflow) {
2111 free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
2112 } else {
2113 free_stack = 0xffffff;
2114 }
2115
2116 for (i = clause_index_start; i < ji->num_clauses; i++) {
2117 MonoJitExceptionInfo *ei = &ji->clauses [i];
2118 gboolean filtered = FALSE;
2119
2120 /*
2121 * During stack overflow, wait till the unwinding frees some stack
2122 * space before running handlers/finalizers.
2123 */
2124 if (free_stack <= (64 * 1024))
2125 continue;
2126
2127 if (is_address_protected (ji, ei, ip)) {
2128 /* catch block */
2129 MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx);
2130
2131 /*
2132 * Have to unwrap RuntimeWrappedExceptions if the
2133 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
2134 */
2135 if (non_exception && !wrap_non_exception_throws (method))
2136 ex_obj = non_exception;
2137 else
2138 ex_obj = obj;
2139
2140 if (((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER))) {
2141 #ifndef MONO_CROSS_COMPILE
2142 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
2143 MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj);
2144 #else
2145 g_assert (!ji->from_llvm);
2146 /* store the exception object in bp + ei->exvar_offset */
2147 *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj;
2148 #endif
2149 #endif
2150 }
2151
2152 #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG
2153 if (ji->from_llvm)
2154 MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index);
2155 #endif
2156
2157 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
2158 /*
2159 * Filter clauses should only be run in the
2160 * first pass of exception handling.
2161 */
2162 filtered = (filter_idx == first_filter_idx);
2163 filter_idx ++;
2164 }
2165
2166 error_init (&error);
2167 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
2168 mono_object_isinst_checked (ex_obj, catch_class, &error)) || filtered) {
2169 /*
2170 * This guards against the situation that we abort a thread that is executing a finally clause
2171 * that was called by the EH machinery. It won't have a guard trampoline installed, so we must
2172 * check for this situation here and resume interruption if we are below the guarded block.
2173 */
2174 if (G_UNLIKELY (jit_tls->handler_block)) {
2175 gboolean is_outside = FALSE;
2176 gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context);
2177 gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx);
2178 //FIXME make this stack direction aware
2179
2180 if (catch_bp > prot_bp) {
2181 is_outside = TRUE;
2182 } else if (catch_bp == prot_bp) {
2183 /* Can be either try { try { } catch {} } finally {} or try { try { } finally {} } catch {}
2184 * So we check if the catch handler_start is protected by the guarded handler protected region
2185 *
2186 * Assumptions:
2187 * If there is an outstanding guarded_block return address, it means the current thread must be aborted.
2188 * This is the only way to reach out the guarded block as other cases are handled by the trampoline.
2189 * There aren't any further finally/fault handler blocks down the stack over this exception.
2190 * This must be ensured by the code that installs the guard trampoline.
2191 */
2192 g_assert (ji == mini_jit_info_table_find (domain, (char *)MONO_CONTEXT_GET_IP (&jit_tls->handler_block_context), NULL));
2193
2194 if (!is_address_protected (ji, jit_tls->handler_block, ei->handler_start)) {
2195 is_outside = TRUE;
2196 }
2197 }
2198 if (is_outside) {
2199 jit_tls->handler_block = NULL;
2200 mono_thread_resume_interruption (TRUE); /*We ignore the exception here, it will be raised later*/
2201 }
2202 }
2203
2204 if (mono_trace_is_enabled () && mono_trace_eval (method))
2205 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2206 jit_tls->orig_ex_ctx_set = TRUE;
2207 MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj));
2208 jit_tls->orig_ex_ctx_set = FALSE;
2209 mini_set_abort_threshold (ctx);
2210
2211 if (in_interp) {
2212 /*
2213 * ctx->pc points into the interpreter, after the call which transitioned to
2214 * JITted code. Store the unwind state into the
2215 * interpeter state, then resume, the interpreter will unwind itself until
2216 * it reaches the target frame and will continue execution from there.
2217 * The resuming is kinda hackish, from the native code standpoint, it looks
2218 * like the call which transitioned to JITted code has succeeded, but the
2219 * return value register etc. is not set, so we have to be careful.
2220 */
2221 mini_get_interp_callbacks ()->set_resume_state (jit_tls, mono_ex, ei, frame.interp_frame, ei->handler_start);
2222 /* Undo the IP adjustment done by mono_arch_unwind_frame () */
2223 #if defined(TARGET_AMD64)
2224 ctx->gregs [AMD64_RIP] ++;
2225 #elif defined(TARGET_ARM)
2226 ctx->pc ++;
2227 if (mono_arm_thumb_supported ())
2228 ctx->pc |= 1;
2229 #elif defined(TARGET_ARM64)
2230 ctx->pc ++;
2231 #elif defined (HOST_WASM)
2232 //nada?
2233 #else
2234 NOT_IMPLEMENTED;
2235 #endif
2236 } else {
2237 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2238 }
2239 mono_set_lmf (lmf);
2240 #ifndef DISABLE_PERFCOUNTERS
2241 mono_atomic_fetch_add_i32 (&mono_perfcounters->exceptions_depth, frame_count);
2242 #endif
2243 if (obj == (MonoObject *)domain->stack_overflow_ex)
2244 jit_tls->handling_stack_ovf = FALSE;
2245
2246 return 0;
2247 }
2248 mono_error_cleanup (&error);
2249 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
2250 if (mono_trace_is_enabled () && mono_trace_eval (method))
2251 g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2252 jit_tls->orig_ex_ctx_set = TRUE;
2253 MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj));
2254 jit_tls->orig_ex_ctx_set = FALSE;
2255 }
2256 if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2257 if (mono_trace_is_enabled () && mono_trace_eval (method))
2258 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE));
2259 jit_tls->orig_ex_ctx_set = TRUE;
2260 MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj));
2261 jit_tls->orig_ex_ctx_set = FALSE;
2262 #ifndef DISABLE_PERFCOUNTERS
2263 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_finallys);
2264 #endif
2265 }
2266 if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
2267 mono_set_lmf (lmf);
2268 if (ji->from_llvm) {
2269 /*
2270 * LLVM compiled finally handlers follow the design
2271 * of the c++ ehabi, i.e. they call a resume function
2272 * at the end instead of returning to the caller.
2273 * So save the exception handling state,
2274 * mono_resume_unwind () will call us again to continue
2275 * the unwinding.
2276 */
2277 jit_tls->resume_state.ex_obj = obj;
2278 jit_tls->resume_state.ji = ji;
2279 jit_tls->resume_state.clause_index = i + 1;
2280 jit_tls->resume_state.ctx = *ctx;
2281 jit_tls->resume_state.new_ctx = new_ctx;
2282 jit_tls->resume_state.lmf = lmf;
2283 jit_tls->resume_state.first_filter_idx = first_filter_idx;
2284 jit_tls->resume_state.filter_idx = filter_idx;
2285 mini_set_abort_threshold (ctx);
2286 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
2287 return 0;
2288 } else {
2289 mini_set_abort_threshold (ctx);
2290 if (in_interp) {
2291 gboolean has_ex = mini_get_interp_callbacks ()->run_finally (&frame, i, ei->handler_start);
2292 if (has_ex)
2293 return 0;
2294 } else {
2295 call_filter (ctx, ei->handler_start);
2296 }
2297 }
2298 }
2299 }
2300 }
2301
2302 if (MONO_PROFILER_ENABLED (method_exception_leave) &&
2303 mono_profiler_get_call_instrumentation_flags (method) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE) {
2304 jit_tls->orig_ex_ctx_set = TRUE;
2305 MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj));
2306 jit_tls->orig_ex_ctx_set = FALSE;
2307 }
2308
2309 *ctx = new_ctx;
2310 }
2311
2312 g_assert_not_reached ();
2313 }
2314
2315 /**
2316 * mono_debugger_run_finally:
2317 * \param start_ctx saved processor state
2318 * This method is called by the Mono Debugger to call all \c finally clauses of the
2319 * current stack frame. It's used when the user issues a \c return command to make
2320 * the current stack frame return. After returning from this method, the debugger
2321 * unwinds the stack one frame and gives control back to the user.
2322 * NOTE: This method is only used when running inside the Mono Debugger.
2323 */
2324 void
mono_debugger_run_finally(MonoContext * start_ctx)2325 mono_debugger_run_finally (MonoContext *start_ctx)
2326 {
2327 static int (*call_filter) (MonoContext *, gpointer) = NULL;
2328 MonoDomain *domain = mono_domain_get ();
2329 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
2330 MonoLMF *lmf = mono_get_lmf ();
2331 MonoContext ctx, new_ctx;
2332 MonoJitInfo *ji, rji;
2333 int i;
2334
2335 ctx = *start_ctx;
2336
2337 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
2338 if (!ji || ji == (gpointer)-1)
2339 return;
2340
2341 if (!call_filter)
2342 call_filter = (int (*)(MonoContext *, void *))mono_get_call_filter ();
2343
2344 for (i = 0; i < ji->num_clauses; i++) {
2345 MonoJitExceptionInfo *ei = &ji->clauses [i];
2346
2347 if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (&ctx)) &&
2348 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
2349 call_filter (&ctx, ei->handler_start);
2350 }
2351 }
2352 }
2353
2354 /**
2355 * mono_handle_exception:
2356 * \param ctx saved processor state
2357 * \param obj the exception object
2358 *
2359 * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
2360 * return TRUE.
2361 */
2362 gboolean
mono_handle_exception(MonoContext * ctx,MonoObject * obj)2363 mono_handle_exception (MonoContext *ctx, MonoObject *obj)
2364 {
2365 MONO_REQ_GC_UNSAFE_MODE;
2366
2367 #ifndef DISABLE_PERFCOUNTERS
2368 mono_atomic_inc_i32 (&mono_perfcounters->exceptions_thrown);
2369 #endif
2370
2371 return mono_handle_exception_internal (ctx, obj, FALSE, NULL);
2372 }
2373
2374 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
2375
2376 #ifndef MONO_ARCH_USE_SIGACTION
2377 #error "Can't use sigaltstack without sigaction"
2378 #endif
2379
2380 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
2381
2382 void
mono_setup_altstack(MonoJitTlsData * tls)2383 mono_setup_altstack (MonoJitTlsData *tls)
2384 {
2385 size_t stsize = 0;
2386 stack_t sa;
2387 guint8 *staddr = NULL;
2388
2389 if (mono_running_on_valgrind ())
2390 return;
2391
2392 mono_thread_info_get_stack_bounds (&staddr, &stsize);
2393
2394 g_assert (staddr);
2395
2396 tls->end_of_stack = staddr + stsize;
2397 tls->stack_size = stsize;
2398
2399 /*g_print ("thread %p, stack_base: %p, stack_size: %d\n", (gpointer)pthread_self (), staddr, stsize);*/
2400
2401 tls->stack_ovf_guard_base = staddr + mono_pagesize ();
2402 tls->stack_ovf_guard_size = ALIGN_TO (8 * 4096, mono_pagesize ());
2403
2404 g_assert ((guint8*)&sa >= (guint8*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size);
2405
2406 if (mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE)) {
2407 /* mprotect can fail for the main thread stack */
2408 gpointer gaddr = mono_valloc (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_NONE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON|MONO_MMAP_FIXED, MONO_MEM_ACCOUNT_EXCEPTIONS);
2409 g_assert (gaddr == tls->stack_ovf_guard_base);
2410 tls->stack_ovf_valloced = TRUE;
2411 }
2412
2413 /* Setup an alternate signal stack */
2414 tls->signal_stack = mono_valloc (0, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_PRIVATE|MONO_MMAP_ANON, MONO_MEM_ACCOUNT_EXCEPTIONS);
2415 tls->signal_stack_size = MONO_ARCH_SIGNAL_STACK_SIZE;
2416
2417 g_assert (tls->signal_stack);
2418
2419 sa.ss_sp = tls->signal_stack;
2420 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
2421 sa.ss_flags = 0;
2422 g_assert (sigaltstack (&sa, NULL) == 0);
2423
2424 mono_gc_register_altstack ((char*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size, (char*)staddr + stsize - ((char*)tls->stack_ovf_guard_base + tls->stack_ovf_guard_size), tls->signal_stack, tls->signal_stack_size);
2425 }
2426
2427 void
mono_free_altstack(MonoJitTlsData * tls)2428 mono_free_altstack (MonoJitTlsData *tls)
2429 {
2430 stack_t sa;
2431 int err;
2432
2433 sa.ss_sp = tls->signal_stack;
2434 sa.ss_size = MONO_ARCH_SIGNAL_STACK_SIZE;
2435 sa.ss_flags = SS_DISABLE;
2436 err = sigaltstack (&sa, NULL);
2437 g_assert (err == 0);
2438
2439 if (tls->signal_stack)
2440 mono_vfree (tls->signal_stack, MONO_ARCH_SIGNAL_STACK_SIZE, MONO_MEM_ACCOUNT_EXCEPTIONS);
2441 if (tls->stack_ovf_valloced)
2442 mono_vfree (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MEM_ACCOUNT_EXCEPTIONS);
2443 else
2444 mono_mprotect (tls->stack_ovf_guard_base, tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
2445 }
2446
2447 #else /* !MONO_ARCH_SIGSEGV_ON_ALTSTACK */
2448
2449 void
mono_setup_altstack(MonoJitTlsData * tls)2450 mono_setup_altstack (MonoJitTlsData *tls)
2451 {
2452 }
2453
2454 void
mono_free_altstack(MonoJitTlsData * tls)2455 mono_free_altstack (MonoJitTlsData *tls)
2456 {
2457 }
2458
2459 #endif /* MONO_ARCH_SIGSEGV_ON_ALTSTACK */
2460
2461 static gboolean
try_restore_stack_protection(MonoJitTlsData * jit_tls,int extra_bytes)2462 try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
2463 {
2464 gint32 unprotect_size = jit_tls->stack_ovf_guard_size;
2465 /* we need to leave some room for throwing the exception */
2466 while (unprotect_size >= 0 && (char*)jit_tls->stack_ovf_guard_base + unprotect_size > ((char*)&unprotect_size - extra_bytes))
2467 unprotect_size -= mono_pagesize ();
2468 /* at this point we could try and build a new domain->stack_overflow_ex, but only if there
2469 * is sufficient stack
2470 */
2471 //fprintf (stderr, "restoring stack protection: %p-%p (%d)\n", jit_tls->stack_ovf_guard_base, (char*)jit_tls->stack_ovf_guard_base + unprotect_size, unprotect_size);
2472 if (unprotect_size)
2473 mono_mprotect (jit_tls->stack_ovf_guard_base, unprotect_size, MONO_MMAP_NONE);
2474 return unprotect_size == jit_tls->stack_ovf_guard_size;
2475 }
2476
2477 static G_GNUC_UNUSED void
try_more_restore(void)2478 try_more_restore (void)
2479 {
2480 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
2481 if (try_restore_stack_protection (jit_tls, 500))
2482 jit_tls->restore_stack_prot = NULL;
2483 }
2484
2485 static G_GNUC_UNUSED void
restore_stack_protection(void)2486 restore_stack_protection (void)
2487 {
2488 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
2489 MonoException *ex = mono_domain_get ()->stack_overflow_ex;
2490 /* if we can't restore the stack protection, keep a callback installed so
2491 * we'll try to restore as much stack as we can at each return from unmanaged
2492 * code.
2493 */
2494 if (try_restore_stack_protection (jit_tls, 4096))
2495 jit_tls->restore_stack_prot = NULL;
2496 else
2497 jit_tls->restore_stack_prot = try_more_restore_tramp;
2498 /* here we also throw a stack overflow exception */
2499 ex->trace_ips = NULL;
2500 ex->stack_trace = NULL;
2501 mono_raise_exception_deprecated (ex);
2502 }
2503
2504 gpointer
mono_altstack_restore_prot(mgreg_t * regs,guint8 * code,gpointer * tramp_data,guint8 * tramp)2505 mono_altstack_restore_prot (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
2506 {
2507 MONO_REQ_GC_UNSAFE_MODE;
2508
2509 void (*func)(void) = (void (*)(void))tramp_data;
2510 func ();
2511 return NULL;
2512 }
2513
2514 gboolean
mono_handle_soft_stack_ovf(MonoJitTlsData * jit_tls,MonoJitInfo * ji,void * ctx,MONO_SIG_HANDLER_INFO_TYPE * siginfo,guint8 * fault_addr)2515 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr)
2516 {
2517 if (mono_llvm_only)
2518 return FALSE;
2519
2520 /* we got a stack overflow in the soft-guard pages
2521 * There are two cases:
2522 * 1) managed code caused the overflow: we unprotect the soft-guard page
2523 * and let the arch-specific code trigger the exception handling mechanism
2524 * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
2525 * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
2526 * and hope we can continue with those enabled, at least until the hard-guard page
2527 * is hit. The alternative to continuing here is to just print a message and abort.
2528 * We may add in the future the code to protect the pages again in the codepath
2529 * when we return from unmanaged to managed code.
2530 */
2531 if (jit_tls->stack_ovf_guard_size && fault_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
2532 fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
2533 /* we unprotect the minimum amount we can */
2534 guint32 guard_size;
2535 gboolean handled = FALSE;
2536
2537 guard_size = jit_tls->stack_ovf_guard_size - (mono_pagesize () * SIZEOF_VOID_P / 4);
2538 while (guard_size && fault_addr < (guint8*)jit_tls->stack_ovf_guard_base + guard_size) {
2539 guard_size -= mono_pagesize ();
2540 }
2541 guard_size = jit_tls->stack_ovf_guard_size - guard_size;
2542 /*fprintf (stderr, "unprotecting: %d\n", guard_size);*/
2543 mono_mprotect ((char*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size - guard_size, guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE);
2544 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
2545 if (ji) {
2546 mono_arch_handle_altstack_exception (ctx, siginfo, fault_addr, TRUE);
2547 handled = TRUE;
2548 }
2549 #endif
2550 if (!handled) {
2551 /* We print a message: after this even managed stack overflows
2552 * may crash the runtime
2553 */
2554 mono_runtime_printf_err ("Stack overflow in unmanaged: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
2555 if (!jit_tls->handling_stack_ovf) {
2556 jit_tls->restore_stack_prot = restore_stack_protection_tramp;
2557 jit_tls->handling_stack_ovf = 1;
2558 } else {
2559 /*fprintf (stderr, "Already handling stack overflow\n");*/
2560 }
2561 }
2562 return TRUE;
2563 }
2564 return FALSE;
2565 }
2566
2567 typedef struct {
2568 MonoMethod *omethod;
2569 int count;
2570 } PrintOverflowUserData;
2571
2572 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2573 static gboolean
print_overflow_stack_frame(StackFrameInfo * frame,MonoContext * ctx,gpointer data)2574 print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2575 {
2576 MonoMethod *method = NULL;
2577 PrintOverflowUserData *user_data = (PrintOverflowUserData *)data;
2578 gchar *location;
2579
2580 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
2581 method = jinfo_get_method (frame->ji);
2582
2583 if (method) {
2584 if (user_data->count == 0) {
2585 /* The first frame is in its prolog, so a line number cannot be computed */
2586 user_data->count ++;
2587 return FALSE;
2588 }
2589
2590 /* If this is a one method overflow, skip the other instances */
2591 if (method == user_data->omethod)
2592 return FALSE;
2593
2594 location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2595 mono_runtime_printf_err (" %s", location);
2596 g_free (location);
2597
2598 if (user_data->count == 1) {
2599 mono_runtime_printf_err (" <...>");
2600 user_data->omethod = method;
2601 } else {
2602 user_data->omethod = NULL;
2603 }
2604
2605 user_data->count ++;
2606 } else
2607 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame->native_offset);
2608
2609 return FALSE;
2610 }
2611 #endif
2612
2613 void
mono_handle_hard_stack_ovf(MonoJitTlsData * jit_tls,MonoJitInfo * ji,void * ctx,guint8 * fault_addr)2614 mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, guint8* fault_addr)
2615 {
2616 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2617 PrintOverflowUserData ud;
2618 MonoContext mctx;
2619 #endif
2620
2621 /* we don't do much now, but we can warn the user with a useful message */
2622 mono_runtime_printf_err ("Stack overflow: IP: %p, fault addr: %p", mono_arch_ip_from_context (ctx), fault_addr);
2623
2624 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2625 mono_sigctx_to_monoctx (ctx, &mctx);
2626
2627 mono_runtime_printf_err ("Stacktrace:");
2628
2629 memset (&ud, 0, sizeof (ud));
2630
2631 mono_walk_stack_with_ctx (print_overflow_stack_frame, &mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
2632 #else
2633 if (ji && !ji->is_trampoline && jinfo_get_method (ji))
2634 mono_runtime_printf_err ("At %s", mono_method_full_name (jinfo_get_method (ji), TRUE));
2635 else
2636 mono_runtime_printf_err ("At <unmanaged>.");
2637 #endif
2638
2639 _exit (1);
2640 }
2641
2642 static gboolean
print_stack_frame_to_stderr(StackFrameInfo * frame,MonoContext * ctx,gpointer data)2643 print_stack_frame_to_stderr (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2644 {
2645 MonoMethod *method = NULL;
2646
2647 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
2648 method = jinfo_get_method (frame->ji);
2649
2650 if (method) {
2651 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, mono_domain_get ());
2652 mono_runtime_printf_err (" %s", location);
2653 g_free (location);
2654 } else
2655 mono_runtime_printf_err (" at <unknown> <0x%05x>", frame->native_offset);
2656
2657 return FALSE;
2658 }
2659
2660 static G_GNUC_UNUSED gboolean
print_stack_frame_to_string(StackFrameInfo * frame,MonoContext * ctx,gpointer data)2661 print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2662 {
2663 GString *p = (GString*)data;
2664 MonoMethod *method = NULL;
2665
2666 if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
2667 method = jinfo_get_method (frame->ji);
2668
2669 if (method && frame->domain) {
2670 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
2671 g_string_append_printf (p, " %s\n", location);
2672 g_free (location);
2673 } else
2674 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
2675
2676 return FALSE;
2677 }
2678
2679 #ifndef MONO_CROSS_COMPILE
2680
print_process_map(void)2681 static void print_process_map (void)
2682 {
2683 #ifdef __linux__
2684 FILE *fp = fopen ("/proc/self/maps", "r");
2685 char line [256];
2686
2687 if (fp == NULL) {
2688 mono_runtime_printf_err ("no /proc/self/maps, not on linux?\n");
2689 return;
2690 }
2691
2692 mono_runtime_printf_err ("/proc/self/maps:");
2693
2694 while (fgets (line, sizeof (line), fp)) {
2695 // strip newline
2696 size_t len = strlen (line) - 1;
2697 if (len >= 0 && line [len] == '\n')
2698 line [len] = '\0';
2699
2700 mono_runtime_printf_err ("%s", line);
2701 }
2702
2703 fclose (fp);
2704 #else
2705 /* do nothing */
2706 #endif
2707 }
2708
2709 static gboolean handle_crash_loop = FALSE;
2710
2711 /*
2712 * mono_handle_native_crash:
2713 *
2714 * Handle a native crash (e.g. SIGSEGV) while in native code by
2715 * printing diagnostic information and aborting.
2716 */
2717 void
mono_handle_native_crash(const char * signal,void * ctx,MONO_SIG_HANDLER_INFO_TYPE * info)2718 mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
2719 {
2720 #ifdef MONO_ARCH_USE_SIGACTION
2721 struct sigaction sa;
2722 #endif
2723 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
2724
2725 if (handle_crash_loop)
2726 return;
2727
2728 if (mini_get_debug_options ()->suspend_on_native_crash) {
2729 mono_runtime_printf_err ("Received %s, suspending...", signal);
2730 #ifdef HOST_WIN32
2731 while (1)
2732 ;
2733 #else
2734 while (1) {
2735 sleep (1);
2736 }
2737 #endif
2738 }
2739
2740 /* prevent infinite loops in crash handling */
2741 handle_crash_loop = TRUE;
2742
2743 /* !jit_tls means the thread was not registered with the runtime */
2744 if (jit_tls && mono_thread_internal_current ()) {
2745 mono_runtime_printf_err ("Stacktrace:\n");
2746
2747 /* FIXME: Is MONO_UNWIND_LOOKUP_IL_OFFSET correct here? */
2748 mono_walk_stack (print_stack_frame_to_stderr, MONO_UNWIND_LOOKUP_IL_OFFSET, NULL);
2749 }
2750
2751 print_process_map ();
2752
2753 #ifdef HAVE_BACKTRACE_SYMBOLS
2754 {
2755 void *array [256];
2756 char **names;
2757 int i, size;
2758
2759 mono_runtime_printf_err ("\nNative stacktrace:\n");
2760
2761 size = backtrace (array, 256);
2762 names = backtrace_symbols (array, size);
2763 for (i =0; i < size; ++i) {
2764 mono_runtime_printf_err ("\t%s", names [i]);
2765 }
2766 g_free (names);
2767
2768 /* Try to get more meaningful information using gdb */
2769
2770 #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && defined(SYS_fork)
2771 if (!mini_get_debug_options ()->no_gdb_backtrace) {
2772 /* From g_spawn_command_line_sync () in eglib */
2773 pid_t pid;
2774 int status;
2775 pid_t crashed_pid = getpid ();
2776
2777 /*
2778 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
2779 * it will deadlock. Call the syscall directly instead.
2780 */
2781 #if defined(HOST_ANDROID)
2782 /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */
2783 g_assert_not_reached ();
2784 #elif !defined(HOST_DARWIN) && defined(SYS_fork)
2785 pid = (pid_t) syscall (SYS_fork);
2786 #elif defined(HOST_DARWIN) && HAVE_FORK
2787 pid = (pid_t) fork ();
2788 #else
2789 g_assert_not_reached ();
2790 #endif
2791
2792 #if defined (HAVE_PRCTL) && defined(PR_SET_PTRACER)
2793 if (pid > 0) {
2794 // Allow gdb to attach to the process even if ptrace_scope sysctl variable is set to
2795 // a value other than 0 (the most permissive ptrace scope). Most modern Linux
2796 // distributions set the scope to 1 which allows attaching only to direct children of
2797 // the current process
2798 prctl (PR_SET_PTRACER, pid, 0, 0, 0);
2799 }
2800 #endif
2801
2802 #if defined(TARGET_OSX)
2803 if (mono_merp_enabled ()) {
2804 if (pid == 0) {
2805 MonoContext mctx;
2806 if (!ctx) {
2807 mono_runtime_printf_err ("\nMust always pass non-null context when using merp.\n");
2808 exit (1);
2809 }
2810
2811 mono_sigctx_to_monoctx (ctx, &mctx);
2812
2813 intptr_t thread_pointer = (intptr_t) MONO_CONTEXT_GET_SP (&mctx);
2814
2815 mono_merp_invoke (crashed_pid, thread_pointer, signal);
2816
2817 exit (1);
2818 }
2819 }
2820 #endif
2821
2822 if (pid == 0) {
2823 dup2 (STDERR_FILENO, STDOUT_FILENO);
2824
2825 mono_gdb_render_native_backtraces (crashed_pid);
2826 exit (1);
2827 }
2828
2829 mono_runtime_printf_err ("\nDebug info from gdb:\n");
2830 waitpid (pid, &status, 0);
2831 }
2832 #endif
2833 }
2834 #else
2835 #ifdef HOST_ANDROID
2836 /* set DUMPABLE for this process so debuggerd can attach with ptrace(2), see:
2837 * https://android.googlesource.com/platform/bionic/+/151da681000c07da3c24cd30a3279b1ca017f452/linker/debugger.cpp#206
2838 * this has changed on later versions of Android. Also, we don't want to
2839 * set this on start-up as DUMPABLE has security implications. */
2840 prctl (PR_SET_DUMPABLE, 1);
2841
2842 mono_runtime_printf_err ("\nNo native Android stacktrace (see debuggerd output).\n");
2843 #endif
2844 #endif
2845
2846 /*
2847 * A SIGSEGV indicates something went very wrong so we can no longer depend
2848 * on anything working. So try to print out lots of diagnostics, starting
2849 * with ones which have a greater chance of working.
2850 */
2851 mono_runtime_printf_err (
2852 "\n"
2853 "=================================================================\n"
2854 "Got a %s while executing native code. This usually indicates\n"
2855 "a fatal error in the mono runtime or one of the native libraries \n"
2856 "used by your application.\n"
2857 "=================================================================\n",
2858 signal);
2859
2860 #ifdef MONO_ARCH_USE_SIGACTION
2861 sa.sa_handler = SIG_DFL;
2862 sigemptyset (&sa.sa_mask);
2863 sa.sa_flags = 0;
2864
2865 /* Remove our SIGABRT handler */
2866 g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
2867
2868 /* On some systems we get a SIGILL when calling abort (), because it might
2869 * fail to raise SIGABRT */
2870 g_assert (sigaction (SIGILL, &sa, NULL) != -1);
2871 #endif
2872
2873 if (!mono_do_crash_chaining) {
2874 /*Android abort is a fluke, it doesn't abort, it triggers another segv. */
2875 #if defined (HOST_ANDROID)
2876 exit (-1);
2877 #else
2878 abort ();
2879 #endif
2880 }
2881 }
2882
2883 #else
2884
2885 void
mono_handle_native_crash(const char * signal,void * ctx,MONO_SIG_HANDLER_INFO_TYPE * info)2886 mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
2887 {
2888 g_assert_not_reached ();
2889 }
2890
2891 #endif /* !MONO_CROSS_COMPILE */
2892
2893 static void
mono_print_thread_dump_internal(void * sigctx,MonoContext * start_ctx)2894 mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx)
2895 {
2896 MonoInternalThread *thread = mono_thread_internal_current ();
2897 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2898 MonoContext ctx;
2899 #endif
2900 GString* text;
2901 char *name;
2902 GError *error = NULL;
2903
2904 if (!thread)
2905 return;
2906
2907 text = g_string_new (0);
2908 if (thread->name) {
2909 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
2910 g_assert (!error);
2911 g_string_append_printf (text, "\n\"%s\"", name);
2912 g_free (name);
2913 }
2914 else if (thread->threadpool_thread)
2915 g_string_append (text, "\n\"<threadpool thread>\"");
2916 else
2917 g_string_append (text, "\n\"<unnamed thread>\"");
2918
2919 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
2920 mono_thread_internal_describe (thread, text);
2921 g_string_append (text, "\n");
2922
2923 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
2924 if (start_ctx) {
2925 memcpy (&ctx, start_ctx, sizeof (MonoContext));
2926 } else if (!sigctx)
2927 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, mono_print_thread_dump);
2928 else
2929 mono_sigctx_to_monoctx (sigctx, &ctx);
2930
2931 mono_walk_stack_with_ctx (print_stack_frame_to_string, &ctx, MONO_UNWIND_LOOKUP_ALL, text);
2932 #else
2933 mono_runtime_printf ("\t<Stack traces in thread dumps not supported on this platform>");
2934 #endif
2935
2936 mono_runtime_printf ("%s", text->str);
2937
2938 #if HOST_WIN32 && TARGET_WIN32 && _DEBUG
2939 OutputDebugStringA(text->str);
2940 #endif
2941
2942 g_string_free (text, TRUE);
2943 mono_runtime_stdout_fflush ();
2944 }
2945
2946 /**
2947 * mono_print_thread_dump:
2948 *
2949 * Print information about the current thread to stdout.
2950 * \p sigctx can be NULL, allowing this to be called from gdb.
2951 */
2952 void
mono_print_thread_dump(void * sigctx)2953 mono_print_thread_dump (void *sigctx)
2954 {
2955 mono_print_thread_dump_internal (sigctx, NULL);
2956 }
2957
2958 void
mono_print_thread_dump_from_ctx(MonoContext * ctx)2959 mono_print_thread_dump_from_ctx (MonoContext *ctx)
2960 {
2961 mono_print_thread_dump_internal (NULL, ctx);
2962 }
2963
2964 /*
2965 * mono_resume_unwind:
2966 *
2967 * This is called by a trampoline from LLVM compiled finally clauses to continue
2968 * unwinding.
2969 */
2970 void
mono_resume_unwind(MonoContext * ctx)2971 mono_resume_unwind (MonoContext *ctx)
2972 {
2973 MONO_REQ_GC_UNSAFE_MODE;
2974
2975 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
2976 MonoContext new_ctx;
2977
2978 MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
2979 MONO_CONTEXT_SET_SP (ctx, MONO_CONTEXT_GET_SP (&jit_tls->resume_state.ctx));
2980 new_ctx = *ctx;
2981
2982 mono_handle_exception_internal (&new_ctx, (MonoObject *)jit_tls->resume_state.ex_obj, TRUE, NULL);
2983
2984 mono_restore_context (&new_ctx);
2985 }
2986
2987 typedef struct {
2988 MonoJitInfo *ji;
2989 MonoContext ctx;
2990 MonoJitExceptionInfo *ei;
2991 } FindHandlerBlockData;
2992
2993 static gboolean
find_last_handler_block(StackFrameInfo * frame,MonoContext * ctx,gpointer data)2994 find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
2995 {
2996 int i;
2997 gpointer ip;
2998 FindHandlerBlockData *pdata = (FindHandlerBlockData *)data;
2999 MonoJitInfo *ji = frame->ji;
3000
3001 if (!ji)
3002 return FALSE;
3003
3004 ip = MONO_CONTEXT_GET_IP (ctx);
3005
3006 for (i = 0; i < ji->num_clauses; ++i) {
3007 MonoJitExceptionInfo *ei = ji->clauses + i;
3008 if (ei->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3009 continue;
3010 /*If ip points to the first instruction it means the handler block didn't start
3011 so we can leave its execution to the EH machinery*/
3012 if (ei->handler_start <= ip && ip < ei->data.handler_end) {
3013 pdata->ji = ji;
3014 pdata->ei = ei;
3015 pdata->ctx = *ctx;
3016 break;
3017 }
3018 }
3019 return FALSE;
3020 }
3021
3022
3023 static void
install_handler_block_guard(MonoJitInfo * ji,MonoContext * ctx)3024 install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
3025 {
3026 int i;
3027 MonoJitExceptionInfo *clause = NULL;
3028 gpointer ip;
3029 guint8 *bp;
3030
3031 ip = MONO_CONTEXT_GET_IP (ctx);
3032
3033 for (i = 0; i < ji->num_clauses; ++i) {
3034 clause = &ji->clauses [i];
3035 if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
3036 continue;
3037 if (clause->handler_start <= ip && clause->data.handler_end > ip)
3038 break;
3039 }
3040
3041 /*no matching finally */
3042 if (i == ji->num_clauses)
3043 return;
3044
3045 /*Load the spvar*/
3046 bp = (guint8*)MONO_CONTEXT_GET_BP (ctx);
3047 *(bp + clause->exvar_offset) = 1;
3048 }
3049
3050 /*
3051 * Finds the bottom handler block running and install a block guard if needed.
3052 */
3053 static gboolean
mono_install_handler_block_guard(MonoThreadUnwindState * ctx)3054 mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
3055 {
3056 FindHandlerBlockData data = { 0 };
3057 MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS];
3058
3059 /* Guard against a null MonoJitTlsData. This can happens if the thread receives the
3060 * interrupt signal before the JIT has time to initialize its TLS data for the given thread.
3061 */
3062 if (!jit_tls || jit_tls->handler_block)
3063 return FALSE;
3064
3065 /* Do an async safe stack walk */
3066 mono_thread_info_set_is_async_context (TRUE);
3067 mono_walk_stack_with_state (find_last_handler_block, ctx, MONO_UNWIND_NONE, &data);
3068 mono_thread_info_set_is_async_context (FALSE);
3069
3070 if (!data.ji)
3071 return FALSE;
3072
3073 memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext));
3074
3075 install_handler_block_guard (data.ji, &data.ctx);
3076
3077 jit_tls->handler_block = data.ei;
3078
3079 return TRUE;
3080 }
3081
3082 static gboolean
mono_current_thread_has_handle_block_guard(void)3083 mono_current_thread_has_handle_block_guard (void)
3084 {
3085 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3086 return jit_tls && jit_tls->handler_block != NULL;
3087 }
3088
3089 void
mono_set_cast_details(MonoClass * from,MonoClass * to)3090 mono_set_cast_details (MonoClass *from, MonoClass *to)
3091 {
3092 MonoJitTlsData *jit_tls = NULL;
3093
3094 if (mini_get_debug_options ()->better_cast_details) {
3095 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3096 jit_tls->class_cast_from = from;
3097 jit_tls->class_cast_to = to;
3098 }
3099 }
3100
3101
3102 /*returns false if the thread is not attached*/
3103 gboolean
mono_thread_state_init_from_sigctx(MonoThreadUnwindState * ctx,void * sigctx)3104 mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
3105 {
3106 #ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
3107 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3108 if (!thread) {
3109 ctx->valid = FALSE;
3110 return FALSE;
3111 }
3112
3113 if (sigctx) {
3114 mono_sigctx_to_monoctx (sigctx, &ctx->ctx);
3115
3116 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3117 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3118 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3119 }
3120 else {
3121 mono_thread_state_init (ctx);
3122 }
3123
3124 if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF])
3125 return FALSE;
3126
3127 ctx->valid = TRUE;
3128 return TRUE;
3129 #else
3130 g_error ("Implement mono_arch_sigctx_to_monoctx for the current target");
3131 return FALSE;
3132 #endif
3133 }
3134
3135 void
mono_thread_state_init(MonoThreadUnwindState * ctx)3136 mono_thread_state_init (MonoThreadUnwindState *ctx)
3137 {
3138 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3139
3140 #if defined(MONO_CROSS_COMPILE)
3141 ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
3142 #elif MONO_ARCH_HAS_MONO_CONTEXT
3143 MONO_CONTEXT_GET_CURRENT (ctx->ctx);
3144 #else
3145 g_error ("Use a null sigctx requires a working mono-context");
3146 #endif
3147
3148 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3149 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3150 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
3151 ctx->valid = TRUE;
3152 }
3153
3154
3155 gboolean
mono_thread_state_init_from_monoctx(MonoThreadUnwindState * ctx,MonoContext * mctx)3156 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
3157 {
3158 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3159 if (!thread) {
3160 ctx->valid = FALSE;
3161 return FALSE;
3162 }
3163
3164 ctx->ctx = *mctx;
3165 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3166 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3167 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3168 ctx->valid = TRUE;
3169 return TRUE;
3170 }
3171
3172 /*returns false if the thread is not attached*/
3173 gboolean
mono_thread_state_init_from_current(MonoThreadUnwindState * ctx)3174 mono_thread_state_init_from_current (MonoThreadUnwindState *ctx)
3175 {
3176 MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
3177 MONO_ARCH_CONTEXT_DEF
3178
3179 mono_arch_flush_register_windows ();
3180
3181 if (!thread || !thread->jit_data) {
3182 ctx->valid = FALSE;
3183 return FALSE;
3184 }
3185 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
3186 MONO_INIT_CONTEXT_FROM_CURRENT (&ctx->ctx);
3187 #else
3188 MONO_INIT_CONTEXT_FROM_FUNC (&ctx->ctx, mono_thread_state_init_from_current);
3189 #endif
3190
3191 ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
3192 ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
3193 ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
3194 ctx->valid = TRUE;
3195 return TRUE;
3196 }
3197
3198 static void
mono_raise_exception_with_ctx(MonoException * exc,MonoContext * ctx)3199 mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
3200 {
3201 mono_handle_exception (ctx, (MonoObject *)exc);
3202 mono_restore_context (ctx);
3203 }
3204
3205 /*FIXME Move all monoctx -> sigctx conversion to signal handlers once all archs support utils/mono-context */
3206 void
mono_setup_async_callback(MonoContext * ctx,void (* async_cb)(void * fun),gpointer user_data)3207 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
3208 {
3209 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
3210 MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
3211 jit_tls->ex_ctx = *ctx;
3212
3213 mono_arch_setup_async_callback (ctx, async_cb, user_data);
3214 #else
3215 g_error ("This target doesn't support mono_arch_setup_async_callback");
3216 #endif
3217 }
3218
3219 /*
3220 * mono_restore_context:
3221 *
3222 * Call the architecture specific restore context function.
3223 */
3224 void
mono_restore_context(MonoContext * ctx)3225 mono_restore_context (MonoContext *ctx)
3226 {
3227 static void (*restore_context) (MonoContext *);
3228
3229 if (!restore_context)
3230 restore_context = (void (*)(MonoContext *))mono_get_restore_context ();
3231 restore_context (ctx);
3232 g_assert_not_reached ();
3233 }
3234
3235 /*
3236 * mono_jinfo_get_unwind_info:
3237 *
3238 * Return the unwind info for JI.
3239 */
3240 guint8*
mono_jinfo_get_unwind_info(MonoJitInfo * ji,guint32 * unwind_info_len)3241 mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
3242 {
3243 if (ji->has_unwind_info) {
3244 /* The address/length in the MonoJitInfo structure itself */
3245 MonoUnwindJitInfo *info = mono_jit_info_get_unwind_info (ji);
3246 *unwind_info_len = info->unw_info_len;
3247 return info->unw_info;
3248 } else if (ji->from_aot)
3249 return mono_aot_get_unwind_info (ji, unwind_info_len);
3250 else
3251 return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len);
3252 }
3253
3254 int
mono_jinfo_get_epilog_size(MonoJitInfo * ji)3255 mono_jinfo_get_epilog_size (MonoJitInfo *ji)
3256 {
3257 MonoArchEHJitInfo *info;
3258
3259 info = mono_jit_info_get_arch_eh_info (ji);
3260 g_assert (info);
3261
3262 return info->epilog_size;
3263 }
3264
3265 /*
3266 * LLVM/Bitcode exception handling.
3267 */
3268
3269 static void
throw_exception(MonoObject * ex,gboolean rethrow)3270 throw_exception (MonoObject *ex, gboolean rethrow)
3271 {
3272 MONO_REQ_GC_UNSAFE_MODE;
3273
3274 MonoError error;
3275 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3276 MonoException *mono_ex;
3277
3278 if (!mono_object_isinst_checked (ex, mono_defaults.exception_class, &error)) {
3279 mono_error_assert_ok (&error);
3280 mono_ex = mono_get_exception_runtime_wrapped_checked (ex, &error);
3281 mono_error_assert_ok (&error);
3282 jit_tls->thrown_non_exc = mono_gchandle_new (ex, FALSE);
3283 }
3284 else
3285 mono_ex = (MonoException*)ex;
3286
3287 // Note: Not pinned
3288 jit_tls->thrown_exc = mono_gchandle_new ((MonoObject*)mono_ex, FALSE);
3289
3290 if (!rethrow) {
3291 #ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
3292 GList *l, *ips = NULL;
3293 GList *trace;
3294
3295 _Unwind_Backtrace (build_stack_trace, &ips);
3296 /* The list contains ip-gshared info pairs */
3297 trace = NULL;
3298 ips = g_list_reverse (ips);
3299 for (l = ips; l; l = l->next) {
3300 trace = g_list_append (trace, l->data);
3301 trace = g_list_append (trace, NULL);
3302 trace = g_list_append (trace, NULL);
3303 }
3304 MonoArray *ips_arr = mono_glist_to_array (trace, mono_defaults.int_class, &error);
3305 mono_error_assert_ok (&error);
3306 MONO_OBJECT_SETREF (mono_ex, trace_ips, ips_arr);
3307 g_list_free (l);
3308 g_list_free (trace);
3309 #endif
3310 }
3311
3312 mono_llvm_cpp_throw_exception ();
3313 }
3314
3315 void
mono_llvm_throw_exception(MonoObject * ex)3316 mono_llvm_throw_exception (MonoObject *ex)
3317 {
3318 throw_exception (ex, FALSE);
3319 }
3320
3321 void
mono_llvm_rethrow_exception(MonoObject * ex)3322 mono_llvm_rethrow_exception (MonoObject *ex)
3323 {
3324 throw_exception (ex, TRUE);
3325 }
3326
3327 void
mono_llvm_raise_exception(MonoException * e)3328 mono_llvm_raise_exception (MonoException *e)
3329 {
3330 mono_llvm_throw_exception ((MonoObject*)e);
3331 }
3332
3333 void
mono_llvm_reraise_exception(MonoException * e)3334 mono_llvm_reraise_exception (MonoException *e)
3335 {
3336 mono_llvm_rethrow_exception ((MonoObject*)e);
3337 }
3338
3339 void
mono_llvm_throw_corlib_exception(guint32 ex_token_index)3340 mono_llvm_throw_corlib_exception (guint32 ex_token_index)
3341 {
3342 guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
3343 MonoException *ex;
3344
3345 ex = mono_exception_from_token (mono_defaults.exception_class->image, ex_token);
3346
3347 mono_llvm_throw_exception ((MonoObject*)ex);
3348 }
3349
3350 /*
3351 * mono_llvm_resume_exception:
3352 *
3353 * Resume exception propagation.
3354 */
3355 void
mono_llvm_resume_exception(void)3356 mono_llvm_resume_exception (void)
3357 {
3358 mono_llvm_cpp_throw_exception ();
3359 }
3360
3361 /*
3362 * mono_llvm_load_exception:
3363 *
3364 * Return the currently thrown exception.
3365 */
3366 MonoObject *
mono_llvm_load_exception(void)3367 mono_llvm_load_exception (void)
3368 {
3369 MonoError error;
3370 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3371
3372 MonoException *mono_ex = (MonoException*)mono_gchandle_get_target (jit_tls->thrown_exc);
3373
3374 if (mono_ex->trace_ips) {
3375 GList *trace_ips = NULL;
3376 gpointer ip = MONO_RETURN_ADDRESS ();
3377
3378 size_t upper = mono_array_length (mono_ex->trace_ips);
3379
3380 for (int i = 0; i < upper; i += TRACE_IP_ENTRY_SIZE) {
3381 gpointer curr_ip = mono_array_get (mono_ex->trace_ips, gpointer, i);
3382 for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) {
3383 gpointer p = mono_array_get (mono_ex->trace_ips, gpointer, i + j);
3384 trace_ips = g_list_append (trace_ips, p);
3385 }
3386 if (ip == curr_ip)
3387 break;
3388 }
3389
3390 // FIXME: Does this work correctly for rethrows?
3391 // We may be discarding useful information
3392 // when this gets GC'ed
3393 MonoArray *ips_arr = mono_glist_to_array (trace_ips, mono_defaults.int_class, &error);
3394 mono_error_assert_ok (&error);
3395 MONO_OBJECT_SETREF (mono_ex, trace_ips, ips_arr);
3396 g_list_free (trace_ips);
3397
3398 // FIXME:
3399 //MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
3400 } else {
3401 MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_array_new_checked (mono_domain_get (), mono_defaults.int_class, 0, &error));
3402 mono_error_assert_ok (&error);
3403 MONO_OBJECT_SETREF (mono_ex, stack_trace, mono_array_new_checked (mono_domain_get (), mono_defaults.stack_frame_class, 0, &error));
3404 mono_error_assert_ok (&error);
3405 }
3406
3407 return &mono_ex->object;
3408 }
3409
3410 /*
3411 * mono_llvm_clear_exception:
3412 *
3413 * Mark the currently thrown exception as handled.
3414 */
3415 void
mono_llvm_clear_exception(void)3416 mono_llvm_clear_exception (void)
3417 {
3418 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3419 mono_gchandle_free (jit_tls->thrown_exc);
3420 jit_tls->thrown_exc = 0;
3421 if (jit_tls->thrown_non_exc)
3422 mono_gchandle_free (jit_tls->thrown_non_exc);
3423 jit_tls->thrown_non_exc = 0;
3424
3425 mono_memory_barrier ();
3426 }
3427
3428 /*
3429 * mono_llvm_match_exception:
3430 *
3431 * Return the innermost clause containing REGION_START-REGION_END which can handle
3432 * the current exception.
3433 */
3434 gint32
mono_llvm_match_exception(MonoJitInfo * jinfo,guint32 region_start,guint32 region_end,gpointer rgctx,MonoObject * this_obj)3435 mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
3436 {
3437 MonoError error;
3438 MonoJitTlsData *jit_tls = mono_get_jit_tls ();
3439 MonoObject *exc;
3440 gint32 index = -1;
3441
3442 g_assert (jit_tls->thrown_exc);
3443 exc = mono_gchandle_get_target (jit_tls->thrown_exc);
3444 if (jit_tls->thrown_non_exc) {
3445 /*
3446 * Have to unwrap RuntimeWrappedExceptions if the
3447 * method's assembly doesn't have a RuntimeCompatibilityAttribute.
3448 */
3449 if (!wrap_non_exception_throws (jinfo_get_method (jinfo)))
3450 exc = mono_gchandle_get_target (jit_tls->thrown_non_exc);
3451 }
3452
3453 for (int i = 0; i < jinfo->num_clauses; i++) {
3454 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
3455 MonoClass *catch_class;
3456
3457 if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) )
3458 continue;
3459
3460 catch_class = ei->data.catch_class;
3461 if (mono_class_is_open_constructed_type (&catch_class->byval_arg)) {
3462 MonoGenericContext context;
3463 MonoType *inflated_type;
3464
3465 g_assert (rgctx || this_obj);
3466 context = get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
3467 inflated_type = mono_class_inflate_generic_type_checked (&catch_class->byval_arg, &context, &error);
3468 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3469
3470 catch_class = mono_class_from_mono_type (inflated_type);
3471 mono_metadata_free_type (inflated_type);
3472 }
3473
3474 // FIXME: Handle edge cases handled in get_exception_catch_class
3475 if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (exc, catch_class, &error)) {
3476 index = ei->clause_index;
3477 break;
3478 } else
3479 mono_error_assert_ok (&error);
3480
3481 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
3482 g_assert_not_reached ();
3483 }
3484 }
3485
3486 return index;
3487 }
3488
3489 #ifdef ENABLE_LLVM
3490 _Unwind_Reason_Code
mono_debug_personality(int a,_Unwind_Action b,uint64_t c,struct _Unwind_Exception * d,struct _Unwind_Context * e)3491 mono_debug_personality (int a, _Unwind_Action b,
3492 uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
3493 {
3494 g_assert_not_reached ();
3495 }
3496 #else
3497 void
3498 mono_debug_personality (void);
3499
3500 void
mono_debug_personality(void)3501 mono_debug_personality (void)
3502 {
3503 g_assert_not_reached ();
3504 }
3505 #endif
3506