2 * exception.c: exception support
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2001 Ximian, Inc.
14 #include <mono/arch/x86/x86-codegen.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/mono-debug.h>
24 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
25 # define SC_EAX sc_eax
26 # define SC_EBX sc_ebx
27 # define SC_ECX sc_ecx
28 # define SC_EDX sc_edx
29 # define SC_EBP sc_ebp
30 # define SC_EIP sc_eip
31 # define SC_ESP sc_esp
32 # define SC_EDI sc_edi
33 # define SC_ESI sc_esi
46 typedef struct sigcontext MonoContext;
48 #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->SC_EIP = (long)ip; } while (0);
49 #define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->SC_EBP = (long)bp; } while (0);
50 #define MONO_CONTEXT_SET_EXCREG(ctx,exc) do { (ctx)->SC_ECX = (long)exc; } while (0);
52 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->SC_EIP))
53 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->SC_EBP))
55 #ifdef MONO_USE_EXC_TABLES
57 /*************************************/
58 /* STACK UNWINDING STUFF */
59 /*************************************/
61 /* These definitions are from unwind-dw2.c in glibc 2.2.5 */
64 #define DWARF_FRAME_REGISTERS 17
66 typedef struct frame_state
72 long reg_or_offset[DWARF_FRAME_REGISTERS+1];
73 unsigned short cfa_reg;
74 unsigned short retaddr_column;
75 char saved[DWARF_FRAME_REGISTERS+1];
79 get_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum)
81 switch (dwarf_regnum) {
99 g_assert_not_reached ();
106 set_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum, long value)
108 switch (dwarf_regnum) {
137 g_assert_not_reached ();
141 typedef struct frame_state * (*framesf) (void *, struct frame_state *);
143 static framesf frame_state_for = NULL;
145 static gboolean inited = FALSE;
147 typedef char ** (*get_backtrace_symbols_type) (void *__const *__array, int __size);
149 static get_backtrace_symbols_type get_backtrace_symbols = NULL;
152 init_frame_state_for (void)
157 * There are two versions of __frame_state_for: one in libgcc.a and the
158 * other in glibc.so. We need the version from glibc.
159 * For more info, see this:
160 * http://gcc.gnu.org/ml/gcc/2002-08/msg00192.html
162 if ((module = g_module_open ("libc.so.6", G_MODULE_BIND_LAZY))) {
164 if (!g_module_symbol (module, "__frame_state_for", (gpointer*)&frame_state_for))
165 frame_state_for = NULL;
167 if (!g_module_symbol (module, "backtrace_symbols", (gpointer*)&get_backtrace_symbols)) {
168 get_backtrace_symbols = NULL;
169 frame_state_for = NULL;
172 g_module_close (module);
178 /* mono_has_unwind_info:
180 * Tests if a function has an DWARF exception table able to restore
181 * all caller saved registers.
184 mono_has_unwind_info (MonoMethod *method)
186 struct frame_state state_in;
187 struct frame_state *res;
190 init_frame_state_for ();
192 if (!frame_state_for)
195 g_assert (method->addr);
197 memset (&state_in, 0, sizeof (state_in));
199 /* offset 10 is just a guess, but it works for all methods tested */
200 if ((res = frame_state_for ((char *)method->addr + 10, &state_in))) {
202 if (res->saved [X86_EBX] != 1 ||
203 res->saved [X86_EDI] != 1 ||
204 res->saved [X86_EBP] != 1 ||
205 res->saved [X86_ESI] != 1) {
216 void *return_address;
220 x86_unwind_native_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, struct sigcontext *ctx,
221 struct sigcontext *new_ctx, MonoLMF *lmf, char **trace)
223 struct stack_frame *frame;
226 struct frame_state state_in;
227 struct frame_state *res;
233 init_frame_state_for ();
235 if (!frame_state_for)
238 frame = MONO_CONTEXT_GET_BP (ctx);
240 max_stack = lmf && lmf->method ? lmf : jit_tls->end_of_stack;
244 memset (&state_in, 0, sizeof (state_in));
246 while ((gpointer)frame->next < (gpointer)max_stack) {
247 gpointer ip, addr = frame->return_address;
249 char *tmp, **symbols;
252 ip = MONO_CONTEXT_GET_IP (new_ctx);
253 symbols = get_backtrace_symbols (&ip, 1);
255 tmp = g_strdup_printf ("%s\nin (unmanaged) %s", *trace, symbols [0]);
257 tmp = g_strdup_printf ("in (unmanaged) %s", symbols [0]);
264 if ((res = frame_state_for (addr, &state_in))) {
267 cfa = (gint8*) (get_sigcontext_reg (new_ctx, res->cfa_reg) + res->cfa_offset);
268 frame = (struct stack_frame *)((gint8*)cfa - 8);
269 for (i = 0; i < DWARF_FRAME_REGISTERS + 1; i++) {
270 int how = res->saved[i];
272 g_assert ((how == 0) || (how == 1));
275 val = * (long*) ((gint8*)cfa + res->reg_or_offset[i]);
276 set_sigcontext_reg (new_ctx, i, val);
279 new_ctx->esp = (long)cfa;
281 if (res->saved [X86_EBX] == 1 &&
282 res->saved [X86_EDI] == 1 &&
283 res->saved [X86_EBP] == 1 &&
284 res->saved [X86_ESI] == 1 &&
285 (ji = mono_jit_info_table_find (domain, frame->return_address))) {
286 //printf ("FRAME CFA %s\n", mono_method_full_name (ji->method, TRUE));
291 //printf ("FRAME %p %p %p\n", frame, MONO_CONTEXT_GET_IP (new_ctx), mono_jit_info_table_find (domain, MONO_CONTEXT_GET_IP (new_ctx)));
293 MONO_CONTEXT_SET_IP (new_ctx, frame->return_address);
295 MONO_CONTEXT_SET_BP (new_ctx, frame);
297 /* stop if !frame or when we detect an unexpected managed frame */
298 if (!frame || mono_jit_info_table_find (domain, frame->return_address)) {
309 //g_assert_not_reached ();
321 * arch_get_restore_context:
323 * Returns a pointer to a method which restores a previously saved sigcontext.
326 arch_get_restore_context (void)
328 static guint8 *start = NULL;
334 /* restore_contect (struct sigcontext *ctx) */
335 /* we do not restore X86_EAX, X86_EDX */
337 start = code = g_malloc (1024);
340 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
342 /* get return address, stored in EDX */
343 x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EIP), 4);
345 x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
347 x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
349 x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
351 x86_mov_reg_membase (code, X86_ESP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESP), 4);
353 x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
354 /* restore ECX. the exception object is passed here to the catch handler */
355 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ECX), 4);
357 /* jump to the saved IP */
358 x86_jump_reg (code, X86_EDX);
364 * arch_get_call_filter:
366 * Returns a pointer to a method which calls an exception filter. We
367 * also use this function to call finally handlers (we pass NULL as
368 * @exc object in this case).
371 arch_get_call_filter (void)
373 static guint8 start [64];
374 static int inited = 0;
381 /* call_filter (struct sigcontext *ctx, unsigned long eip, gpointer exc) */
384 x86_push_reg (code, X86_EBP);
385 x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
386 x86_push_reg (code, X86_EBX);
387 x86_push_reg (code, X86_EDI);
388 x86_push_reg (code, X86_ESI);
391 x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
393 x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
395 x86_push_reg (code, X86_EBP);
397 x86_push_membase (code, X86_EBP, 16);
399 x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
400 /* restore registers used by global register allocation (EBX & ESI) */
401 x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
402 x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
403 /* save the ESP - this is used by endfinally */
404 x86_mov_membase_reg (code, X86_EBP, mono_exc_esp_offset, X86_ESP, 4);
405 /* call the handler */
406 x86_call_reg (code, X86_ECX);
407 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
409 x86_pop_reg (code, X86_EBP);
410 /* restore saved regs */
411 x86_pop_reg (code, X86_ESI);
412 x86_pop_reg (code, X86_EDI);
413 x86_pop_reg (code, X86_EBX);
417 g_assert ((code - start) < 64);
422 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
423 unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
424 unsigned long eip, unsigned long esp)
426 static void (*restore_context) (struct sigcontext *);
427 struct sigcontext ctx;
429 if (!restore_context)
430 restore_context = arch_get_restore_context ();
432 /* adjust eip so that it point into the call instruction */
445 arch_handle_exception (&ctx, exc, FALSE);
446 restore_context (&ctx);
448 g_assert_not_reached ();
452 * arch_get_throw_exception:
454 * Returns a function pointer which can be used to raise
455 * exceptions. The returned function has the following
456 * signature: void (*func) (MonoException *exc);
457 * For example to raise an arithmetic exception you can use:
459 * x86_push_imm (code, mono_get_exception_arithmetic ());
460 * x86_call_code (code, arch_get_throw_exception ());
464 arch_get_throw_exception (void)
466 static guint8 start [24];
467 static int inited = 0;
476 x86_push_reg (code, X86_ESP);
477 x86_push_membase (code, X86_ESP, 4); /* IP */
478 x86_push_membase (code, X86_ESP, 12); /* exception */
479 x86_push_reg (code, X86_EBP);
480 x86_push_reg (code, X86_EDI);
481 x86_push_reg (code, X86_ESI);
482 x86_push_reg (code, X86_EBX);
483 x86_push_reg (code, X86_EDX);
484 x86_push_reg (code, X86_ECX);
485 x86_push_reg (code, X86_EAX);
486 x86_call_code (code, throw_exception);
487 /* we should never reach this breakpoint */
488 x86_breakpoint (code);
490 g_assert ((code - start) < 24);
495 * arch_get_throw_exception_by_name:
497 * Returns a function pointer which can be used to raise
498 * corlib exceptions. The returned function has the following
499 * signature: void (*func) (char *exc_name);
500 * For example to raise an arithmetic exception you can use:
502 * x86_push_imm (code, "ArithmeticException");
503 * x86_call_code (code, arch_get_throw_exception ());
507 arch_get_throw_exception_by_name ()
509 static guint8 start [32];
510 static int inited = 0;
519 /* fixme: we do not save EAX, EDX, ECD - unsure if we need that */
521 x86_push_membase (code, X86_ESP, 4); /* exception name */
522 x86_push_imm (code, "System");
523 x86_push_imm (code, mono_defaults.exception_class->image);
524 x86_call_code (code, mono_exception_from_name);
525 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
526 /* save the newly create object (overwrite exception name)*/
527 x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
528 x86_jump_code (code, arch_get_throw_exception ());
530 g_assert ((code - start) < 32);
536 glist_to_array (GList *list)
538 MonoDomain *domain = mono_domain_get ();
545 len = g_list_length (list);
546 res = mono_array_new (domain, mono_defaults.int_class, len);
548 for (i = 0; list; list = list->next, i++)
549 mono_array_set (res, gpointer, i, list->data);
554 /* mono_arch_find_jit_info:
556 * This function is used to gather information from @ctx. It return the
557 * MonoJitInfo of the corresponding function, unwinds one stack frame and
558 * stores the resulting context into @new_ctx. It also stores a string
559 * describing the stack location into @trace (if not NULL), and modifies
560 * the @lmf if necessary. @native_offset return the IP offset from the
561 * start of the function or -1 if that info is not available.
564 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoContext *ctx,
565 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
569 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
571 ji = mono_jit_info_table_find (domain, ip);
583 char *source_location, *tmpaddr, *fname;
584 gint32 address, iloffset;
589 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
590 /* remove any unused lmf */
591 *lmf = (*lmf)->previous_lmf;
594 address = (char *)ip - (char *)ji->code_start;
597 *native_offset = address;
600 if (!ji->method->wrapper_type)
604 source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
605 iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
608 tmpaddr = g_strdup_printf ("<0x%05x>", address);
610 tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
612 fname = mono_method_full_name (ji->method, TRUE);
615 *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
617 *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
620 g_free (source_location);
625 /* restore caller saved registers */
626 if (ji->used_regs & X86_EBX_MASK) {
627 new_ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
630 if (ji->used_regs & X86_EDI_MASK) {
631 new_ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
634 if (ji->used_regs & X86_ESI_MASK) {
635 new_ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
638 new_ctx->SC_ESP = ctx->SC_EBP;
639 /* we substract 1, so that the IP points into the call instruction */
640 new_ctx->SC_EIP = *((int *)ctx->SC_EBP + 1) - 1;
641 new_ctx->SC_EBP = *((int *)ctx->SC_EBP);
645 #ifdef MONO_USE_EXC_TABLES
646 } else if ((ji = x86_unwind_native_frame (domain, jit_tls, ctx, new_ctx, *lmf, trace))) {
658 *trace = g_strdup_printf ("in (unmanaged) %s", mono_method_full_name ((*lmf)->method, TRUE));
661 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
664 memset (res, 0, sizeof (MonoJitInfo));
665 res->method = (*lmf)->method;
668 new_ctx->SC_ESI = (*lmf)->esi;
669 new_ctx->SC_EDI = (*lmf)->edi;
670 new_ctx->SC_EBX = (*lmf)->ebx;
671 new_ctx->SC_EBP = (*lmf)->ebp;
672 new_ctx->SC_EIP = (*lmf)->eip;
673 /* the lmf is always stored on the stack, so the following
674 * expression points to a stack location which can be used as ESP */
675 new_ctx->SC_ESP = (unsigned long)&((*lmf)->eip);
677 *lmf = (*lmf)->previous_lmf;
687 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
689 MonoDomain *domain = mono_domain_get ();
691 MonoArray *ta = exc->trace_ips;
695 /* Exception is not thrown yet */
696 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
699 len = mono_array_length (ta);
701 res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
703 for (i = skip; i < len; i++) {
705 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
706 gpointer ip = mono_array_get (ta, gpointer, i);
708 ji = mono_jit_info_table_find (domain, ip);
710 /* Unmanaged frame */
711 mono_array_set (res, gpointer, i, sf);
715 g_assert (ji != NULL);
717 sf->method = mono_method_get_object (domain, ji->method, NULL);
718 sf->native_offset = (char *)ip - (char *)ji->code_start;
719 sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain);
721 if (need_file_info) {
724 filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
726 sf->filename = mono_string_new (domain, filename ? filename : "<unknown>");
732 mono_array_set (res, gpointer, i, sf);
739 mono_jit_walk_stack (MonoStackWalk func, gpointer user_data) {
740 MonoDomain *domain = mono_domain_get ();
741 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
742 MonoLMF *lmf = jit_tls->lmf;
743 MonoJitInfo *ji, rji;
744 gint native_offset, il_offset;
747 MonoContext ctx, new_ctx;
749 MONO_CONTEXT_SET_IP (&ctx, __builtin_return_address (0));
750 MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (1));
752 while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
754 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
757 if (ji == (gpointer)-1)
760 il_offset = mono_debug_il_offset_from_address (ji->method, native_offset, domain);
762 if (func (ji->method, native_offset, il_offset, managed, user_data))
770 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
771 MonoReflectionMethod **method,
772 gint32 *iloffset, gint32 *native_offset,
773 MonoString **file, gint32 *line, gint32 *column)
775 MonoDomain *domain = mono_domain_get ();
776 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
777 MonoLMF *lmf = jit_tls->lmf;
778 MonoJitInfo *ji, rji;
779 MonoContext ctx, new_ctx;
781 MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
782 MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (0));
787 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
790 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
793 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)
800 *method = mono_method_get_object (domain, ji->method, NULL);
801 *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset, domain);
803 if (need_file_info) {
806 filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
808 *file = mono_string_new (domain, filename ? filename : "<unknown>");
818 * arch_handle_exception:
819 * @ctx: saved processor state
820 * @obj: the exception object
821 * @test_only: only test if the exception is caught, but dont call handlers
826 arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
828 MonoDomain *domain = mono_domain_get ();
829 MonoJitInfo *ji, rji;
830 static int (*call_filter) (MonoContext *, gpointer, gpointer) = NULL;
831 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
832 MonoLMF *lmf = jit_tls->lmf;
833 GList *trace_ips = NULL;
835 g_assert (ctx != NULL);
837 MonoException *ex = mono_get_exception_null_reference ();
838 ex->message = mono_string_new (domain,
839 "Object reference not set to an instance of an object");
840 obj = (MonoObject *)ex;
843 g_assert (mono_object_isinst (obj, mono_defaults.exception_class));
846 call_filter = arch_get_call_filter ();
848 g_assert (jit_tls->end_of_stack);
849 g_assert (jit_tls->abort_func);
852 MonoContext ctx_cp = *ctx;
853 if (!arch_handle_exception (&ctx_cp, obj, TRUE)) {
854 if (mono_break_on_exc)
856 mono_unhandled_exception (obj);
864 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, ctx, &new_ctx,
865 test_only ? &trace : NULL, &lmf, NULL, NULL);
868 g_warning ("Exception inside function without unwind info");
869 g_assert_not_reached ();
872 if (ji != (gpointer)-1) {
873 if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
876 trace_ips = g_list_append (trace_ips, MONO_CONTEXT_GET_IP (ctx));
878 if (!((MonoException*)obj)->stack_trace)
879 strace = g_strdup ("");
881 strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
883 tmp = g_strdup_printf ("%s%s\n", strace, trace);
886 ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
891 if (ji->num_clauses) {
894 g_assert (ji->clauses);
896 for (i = 0; i < ji->num_clauses; i++) {
897 MonoJitExceptionInfo *ei = &ji->clauses [i];
899 if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
900 MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) {
902 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
903 mono_object_isinst (obj, mono_class_get (ji->method->klass->image, ei->data.token))) ||
904 ((ei->flags == MONO_EXCEPTION_CLAUSE_FILTER &&
905 call_filter (ctx, ei->data.filter, obj)))) {
907 ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
908 g_list_free (trace_ips);
911 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
912 MONO_CONTEXT_SET_EXCREG (ctx, obj);
919 /* no handler found - we need to call all finally handlers */
921 for (i = 0; i < ji->num_clauses; i++) {
922 MonoJitExceptionInfo *ei = &ji->clauses [i];
924 if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
925 MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
926 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
927 call_filter (ctx, ei->handler_start, NULL);
938 if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
941 jit_tls->abort_func (obj);
942 g_assert_not_reached ();
944 ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
945 g_list_free (trace_ips);
951 g_assert_not_reached ();