- Fix atomic ops on s390
[mono.git] / mono / mini / mini-exceptions.c
blobe2b1acfc8d500d4fb69defeb010c813f5f1fd027
1 /*
2 * mini-exceptions.c: generic exception support
4 * Authors:
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2001 Ximian, Inc.
8 */
10 #include <config.h>
11 #include <glib.h>
12 #include <signal.h>
13 #include <string.h>
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/threads.h>
18 #include <mono/metadata/debug-helpers.h>
19 #include <mono/metadata/exception.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/mono-debug.h>
23 #include "mini.h"
25 #define IS_ON_SIGALTSTACK(jit_tls) ((jit_tls) && ((guint8*)&(jit_tls) > (guint8*)(jit_tls)->signal_stack) && ((guint8*)&(jit_tls) < ((guint8*)(jit_tls)->signal_stack + (jit_tls)->signal_stack_size)))
27 #ifndef mono_find_jit_info
29 /* mono_find_jit_info:
31 * This function is used to gather information from @ctx. It return the
32 * MonoJitInfo of the corresponding function, unwinds one stack frame and
33 * stores the resulting context into @new_ctx. It also stores a string
34 * describing the stack location into @trace (if not NULL), and modifies
35 * the @lmf if necessary. @native_offset return the IP offset from the
36 * start of the function or -1 if that info is not available.
38 static MonoJitInfo *
39 mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
40 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
41 gboolean *managed)
43 gboolean managed2;
44 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
45 MonoJitInfo *ji;
47 if (trace)
48 *trace = NULL;
50 if (native_offset)
51 *native_offset = -1;
53 if (managed)
54 *managed = FALSE;
56 ji = mono_arch_find_jit_info (domain, jit_tls, res, prev_ji, ctx, new_ctx, NULL, lmf, NULL, &managed2);
58 if (ji == (gpointer)-1)
59 return ji;
61 if (managed2 || ji->method->wrapper_type) {
62 char *source_location, *tmpaddr, *fname;
63 gint32 address, iloffset;
65 address = (char *)ip - (char *)ji->code_start;
67 if (native_offset)
68 *native_offset = address;
70 if (managed)
71 if (!ji->method->wrapper_type)
72 *managed = TRUE;
74 if (trace) {
75 source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
76 iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
78 if (iloffset < 0)
79 tmpaddr = g_strdup_printf ("<0x%05x>", address);
80 else
81 tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
83 fname = mono_method_full_name (ji->method, TRUE);
85 if (source_location)
86 *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
87 else
88 *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
90 g_free (fname);
91 g_free (source_location);
92 g_free (tmpaddr);
95 else {
96 if (trace) {
97 char *fname = mono_method_full_name (res->method, TRUE);
98 *trace = g_strdup_printf ("in (unmanaged) %s", fname);
99 g_free (fname);
103 return ji;
106 #endif /* mono_find_jit_info */
108 MonoArray *
109 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
111 MonoDomain *domain = mono_domain_get ();
112 MonoArray *res;
113 MonoArray *ta = exc->trace_ips;
114 int i, len;
116 if (ta == NULL) {
117 /* Exception is not thrown yet */
118 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
121 len = mono_array_length (ta);
123 res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
125 for (i = skip; i < len; i++) {
126 MonoJitInfo *ji;
127 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
128 gpointer ip = mono_array_get (ta, gpointer, i);
130 ji = mono_jit_info_table_find (domain, ip);
131 if (ji == NULL) {
132 /* Unmanaged frame */
133 mono_array_set (res, gpointer, i, sf);
134 continue;
137 g_assert (ji != NULL);
139 sf->method = mono_method_get_object (domain, ji->method, NULL);
140 sf->native_offset = (char *)ip - (char *)ji->code_start;
142 sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain);
144 if (need_file_info) {
145 gchar *filename;
147 filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
149 sf->filename = filename? mono_string_new (domain, filename): NULL;
150 sf->column = 0;
152 g_free (filename);
155 mono_array_set (res, gpointer, i, sf);
158 return res;
163 * mono_walk_stack:
164 * @domain: starting appdomain
165 * @jit_tls: JIT data for the thread
166 * @start_ctx: starting state of the stack frame
167 * @func: callback to call for each stack frame
168 * @user_data: data passed to the callback
170 * This function walks the stack of a thread, starting from the state
171 * represented by jit_tls and start_ctx. For each frame the callback
172 * function is called with the relevant info. The walk ends when no more
173 * managed stack frames are found or when the callback returns a TRUE value.
174 * Note that the function can be used to walk the stack of a thread
175 * different from the current.
177 void
178 mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gpointer user_data)
180 MonoLMF *lmf = jit_tls->lmf;
181 MonoJitInfo *ji, rji;
182 gint native_offset;
183 gboolean managed;
184 MonoContext ctx, new_ctx;
186 ctx = *start_ctx;
188 while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
190 * FIXME: mono_find_jit_info () will need to be able to return a different
191 * MonoDomain when apddomain transitions are found on the stack.
193 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
194 if (!ji || ji == (gpointer)-1)
195 return;
197 if (func (domain, &new_ctx, ji, user_data))
198 return;
200 ctx = new_ctx;
204 #ifndef CUSTOM_STACK_WALK
206 void
207 mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data) {
208 MonoDomain *domain = mono_domain_get ();
209 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
210 MonoLMF *lmf = jit_tls->lmf;
211 MonoJitInfo *ji, rji;
212 gint native_offset, il_offset;
213 gboolean managed;
215 MonoContext ctx, new_ctx;
217 mono_arch_flush_register_windows ();
219 MONO_CONTEXT_SET_IP (&ctx, __builtin_return_address (0));
220 MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (1));
222 while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
224 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
225 g_assert (ji);
227 if (ji == (gpointer)-1)
228 return;
230 il_offset = do_il_offset ? mono_debug_il_offset_from_address (ji->method, native_offset, domain): -1;
232 if (func (ji->method, native_offset, il_offset, managed, user_data))
233 return;
235 ctx = new_ctx;
239 MonoBoolean
240 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
241 MonoReflectionMethod **method,
242 gint32 *iloffset, gint32 *native_offset,
243 MonoString **file, gint32 *line, gint32 *column)
245 MonoDomain *domain = mono_domain_get ();
246 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
247 MonoLMF *lmf = jit_tls->lmf;
248 MonoJitInfo *ji, rji;
249 MonoContext ctx, new_ctx;
251 mono_arch_flush_register_windows ();
253 MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
254 MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (0));
256 skip++;
258 do {
259 ji = mono_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
261 ctx = new_ctx;
263 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
264 return FALSE;
266 /* skip all wrappers ??*/
267 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
268 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
269 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
270 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
271 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
272 continue;
274 skip--;
276 } while (skip >= 0);
278 *method = mono_method_get_object (domain, ji->method, NULL);
279 *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset, domain);
281 if (need_file_info) {
282 gchar *filename;
284 filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
286 *file = filename? mono_string_new (domain, filename): NULL;
287 *column = 0;
289 g_free (filename);
292 return TRUE;
295 #endif /* CUSTOM_STACK_WALK */
297 typedef struct {
298 guint32 skips;
299 MonoSecurityFrame *frame;
300 } MonoFrameSecurityInfo;
302 static gboolean
303 callback_get_first_frame_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
305 MonoFrameSecurityInfo *si = (MonoFrameSecurityInfo*) data;
307 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
308 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
309 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
310 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
311 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
312 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
313 return FALSE;
316 if (si->skips > 0) {
317 si->skips--;
318 return FALSE;
321 si->frame = mono_declsec_create_frame (domain, ji);
323 /* Stop - we only want the first frame (e.g. LinkDemand and InheritanceDemand) */
324 return TRUE;
328 * ves_icall_System_Security_SecurityFrame_GetSecurityFrame:
329 * @skip: the number of stack frames to skip
331 * This function returns a the security informations of a single stack frame
332 * (after the skipped ones). This is required for [NonCas]LinkDemand[Choice]
333 * and [NonCas]InheritanceDemand[Choice] as only the caller security is
334 * evaluated.
336 MonoSecurityFrame*
337 ves_icall_System_Security_SecurityFrame_GetSecurityFrame (gint32 skip)
339 MonoDomain *domain = mono_domain_get ();
340 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
341 MonoFrameSecurityInfo si;
342 MonoContext ctx;
344 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
346 si.skips = skip;
347 si.frame = NULL;
348 mono_walk_stack (domain, jit_tls, &ctx, callback_get_first_frame_security_info, (gpointer)&si);
350 return (si.skips == 0) ? si.frame : NULL;
354 typedef struct {
355 guint32 skips;
356 GList *stack;
357 } MonoSecurityStack;
359 static gboolean
360 callback_get_stack_frames_security_info (MonoDomain *domain, MonoContext *ctx, MonoJitInfo *ji, gpointer data)
362 MonoSecurityStack *ss = (MonoSecurityStack*) data;
364 /* FIXME: skip all wrappers ?? probably not - case by case testing is required */
365 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
366 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
367 ji->method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH ||
368 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
369 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE) {
370 return FALSE;
373 if (ss->skips > 0) {
374 ss->skips--;
375 return FALSE;
378 ss->stack = g_list_prepend (ss->stack, mono_declsec_create_frame (domain, ji));
380 /* continue down the stack */
381 return FALSE;
384 static MonoArray *
385 glist_to_array (GList *list, MonoClass *eclass)
387 MonoDomain *domain = mono_domain_get ();
388 MonoArray *res;
389 int len, i;
391 if (!list)
392 return NULL;
394 len = g_list_length (list);
395 res = mono_array_new (domain, eclass, len);
397 for (i = 0; list; list = list->next, i++)
398 mono_array_set (res, gpointer, i, list->data);
400 return res;
404 * ves_icall_System_Security_SecurityFrame_GetSecurityStack:
405 * @skip: the number of stack frames to skip
407 * This function returns an managed array of containing the security
408 * informations for each frame (after the skipped ones). This is used for
409 * [NonCas]Demand[Choice] where the complete evaluation of the stack is
410 * required.
412 MonoArray*
413 ves_icall_System_Security_SecurityFrame_GetSecurityStack (gint32 skip)
415 MonoDomain *domain = mono_domain_get ();
416 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
417 MonoSecurityStack ss;
418 MonoContext ctx;
419 MonoArray *stack;
421 MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_System_Security_SecurityFrame_GetSecurityStack);
423 ss.skips = skip;
424 ss.stack = NULL;
425 mono_walk_stack (domain, jit_tls, &ctx, callback_get_stack_frames_security_info, (gpointer)&ss);
427 stack = glist_to_array (ss.stack, mono_defaults.runtimesecurityframe_class);
428 if (ss.stack)
429 g_list_free (ss.stack);
431 return stack;
434 #ifndef CUSTOM_EXCEPTION_HANDLING
437 * mono_handle_exception:
438 * @ctx: saved processor state
439 * @obj: the exception object
440 * @test_only: only test if the exception is caught, but dont call handlers
443 gboolean
444 mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only)
446 MonoDomain *domain = mono_domain_get ();
447 MonoJitInfo *ji, rji;
448 static int (*call_filter) (MonoContext *, gpointer) = NULL;
449 static void (*restore_context) (void *);
450 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
451 MonoLMF *lmf = jit_tls->lmf;
452 GList *trace_ips = NULL;
453 MonoException *mono_ex;
454 gboolean stack_overflow = FALSE;
455 MonoContext initial_ctx;
456 int frame_count = 0;
457 gboolean gc_disabled = FALSE;
458 MonoString *initial_stack_trace = NULL;
459 GString *trace_str = NULL;
462 * This function might execute on an alternate signal stack, and Boehm GC
463 * can't handle that.
464 * Also, since the altstack is small, stack space intensive operations like
465 * JIT compilation should be avoided.
467 if (IS_ON_SIGALTSTACK (jit_tls)) {
469 * FIXME: disabling/enabling GC while already on a signal stack might
470 * not be safe either.
472 /* Have to reenable it later */
473 gc_disabled = TRUE;
474 mono_gc_disable ();
477 g_assert (ctx != NULL);
478 if (!obj) {
479 MonoException *ex = mono_get_exception_null_reference ();
480 ex->message = mono_string_new (domain, "Object reference not set to an instance of an object");
481 obj = (MonoObject *)ex;
485 * Allocate a new exception object instead of the preconstructed ones.
486 * We can't do this in sigsegv_signal_handler, since GC is not yet
487 * disabled.
489 if (obj == domain->stack_overflow_ex) {
490 obj = mono_get_exception_stack_overflow ();
492 else if (obj == domain->null_reference_ex) {
493 obj = mono_get_exception_null_reference ();
496 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
497 mono_ex = (MonoException*)obj;
498 initial_stack_trace = mono_ex->stack_trace;
499 } else {
500 mono_ex = NULL;
503 if (obj == domain->stack_overflow_ex)
504 stack_overflow = TRUE;
506 if (!call_filter)
507 call_filter = mono_arch_get_call_filter ();
509 if (!restore_context)
510 restore_context = mono_arch_get_restore_context ();
512 g_assert (jit_tls->end_of_stack);
513 g_assert (jit_tls->abort_func);
515 if (!test_only) {
516 MonoContext ctx_cp = *ctx;
517 if (mono_jit_trace_calls != NULL)
518 g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
519 if (!mono_handle_exception (&ctx_cp, obj, original_ip, TRUE)) {
520 if (mono_break_on_exc)
521 G_BREAKPOINT ();
522 mono_unhandled_exception (obj);
524 if (mono_debugger_unhandled_exception (original_ip, MONO_CONTEXT_GET_SP (ctx), obj)) {
526 * If this returns true, then we're running inside the
527 * Mono Debugger and the debugger wants us to restore the
528 * context and continue (normally, the debugger inserts
529 * a breakpoint on the `original_ip', so it regains control
530 * immediately after restoring the context).
532 MONO_CONTEXT_SET_IP (ctx, original_ip);
533 restore_context (ctx);
534 g_assert_not_reached ();
539 initial_ctx = *ctx;
540 memset (&rji, 0, sizeof (rji));
542 while (1) {
543 MonoContext new_ctx;
544 char *trace = NULL;
545 gboolean need_trace = FALSE;
546 guint32 free_stack;
548 if (test_only && (frame_count < 1000)) {
549 need_trace = TRUE;
550 if (!trace_str)
551 trace_str = g_string_new ("");
554 ji = mono_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx,
555 need_trace ? &trace : NULL, &lmf, NULL, NULL);
556 if (!ji) {
557 g_warning ("Exception inside function without unwind info");
558 g_assert_not_reached ();
561 if (ji != (gpointer)-1) {
562 frame_count ++;
563 //printf ("M: %s %d %d.\n", mono_method_full_name (ji->method, TRUE), frame_count, test_only);
565 if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
567 * Avoid overwriting the stack trace if the exception is
568 * rethrown. Also avoid giant stack traces during a stack
569 * overflow.
571 if (!initial_stack_trace && (frame_count < 1000)) {
572 trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
574 g_string_append (trace_str, trace);
575 g_string_append_c (trace_str, '\n');
579 if (stack_overflow)
580 free_stack = (guint8*)(MONO_CONTEXT_GET_BP (ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
581 else
582 free_stack = 0xffffff;
585 * During stack overflow, wait till the unwinding frees some stack
586 * space before running handlers/finalizers.
588 if ((free_stack > (64 * 1024)) && ji->num_clauses) {
589 int i;
591 g_assert (ji->clauses);
593 for (i = 0; i < ji->num_clauses; i++) {
594 MonoJitExceptionInfo *ei = &ji->clauses [i];
595 gboolean filtered = FALSE;
597 #ifdef __s390__
598 if (ei->try_start < MONO_CONTEXT_GET_IP (ctx) &&
599 #else
600 if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
601 #endif
602 MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) {
603 /* catch block */
605 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
606 /* store the exception object int cfg->excvar */
607 g_assert (ji->exvar_offset);
608 *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
609 if (!initial_stack_trace && trace_str) {
610 mono_ex->stack_trace = mono_string_new (domain, trace_str->str);
614 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
615 mono_debugger_handle_exception (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
616 filtered = call_filter (ctx, ei->data.filter);
619 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
620 mono_object_isinst (obj, ei->data.catch_class)) || filtered) {
621 if (test_only) {
622 if (mono_ex) {
623 trace_ips = g_list_reverse (trace_ips);
624 mono_ex->trace_ips = glist_to_array (trace_ips, mono_defaults.int_class);
626 g_list_free (trace_ips);
627 g_free (trace);
629 if (gc_disabled)
630 mono_gc_enable ();
631 if (trace_str)
632 g_string_free (trace_str, TRUE);
633 return TRUE;
635 if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
636 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
637 mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
638 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
639 jit_tls->lmf = lmf;
640 g_free (trace);
642 if (gc_disabled)
643 mono_gc_enable ();
644 if (trace_str)
645 g_string_free (trace_str, TRUE);
646 return 0;
648 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
649 MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
650 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
651 if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
652 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
653 mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
654 call_filter (ctx, ei->handler_start);
662 g_free (trace);
664 *ctx = new_ctx;
666 if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
667 if (gc_disabled)
668 mono_gc_enable ();
670 if (!test_only) {
671 jit_tls->lmf = lmf;
673 if (IS_ON_SIGALTSTACK (jit_tls)) {
674 /* Switch back to normal stack */
675 if (stack_overflow)
676 /* Free up some stack space */
677 MONO_CONTEXT_SET_SP (&initial_ctx, (guint32)(MONO_CONTEXT_GET_SP (&initial_ctx)) + (64 * 1024));
678 MONO_CONTEXT_SET_IP (&initial_ctx, (unsigned int)jit_tls->abort_func);
679 restore_context (&initial_ctx);
681 else
682 jit_tls->abort_func (obj);
683 g_assert_not_reached ();
684 } else {
685 if (mono_ex) {
686 trace_ips = g_list_reverse (trace_ips);
687 mono_ex->trace_ips = glist_to_array (trace_ips, mono_defaults.int_class);
689 g_list_free (trace_ips);
690 if (trace_str)
691 g_string_free (trace_str, TRUE);
692 return FALSE;
697 g_assert_not_reached ();
699 #endif /* CUSTOM_EXECPTION_HANDLING */