2 * exceptions-x86.c: exception support for x86
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2001 Ximian, Inc.
15 #include <mono/arch/x86/x86-codegen.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/threads.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/metadata/gc-internal.h>
22 #include <mono/metadata/mono-debug.h>
27 #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)))
33 /* use SIG* defines if possible */
38 /* sigcontext surrogate */
52 typedef void (* MonoW32ExceptionHandler) (int);
53 void win32_seh_init(void);
54 void win32_seh_cleanup(void);
55 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler);
69 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep);
71 static MonoW32ExceptionHandler fpe_handler;
72 static MonoW32ExceptionHandler ill_handler;
73 static MonoW32ExceptionHandler segv_handler;
75 static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
77 #define W32_SEH_HANDLE_EX(_ex) \
78 if (_ex##_handler) _ex##_handler((int)sctx)
81 * Unhandled Exception Filter
82 * Top-level per-process exception handler.
84 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
88 struct sigcontext* sctx;
91 res = EXCEPTION_CONTINUE_EXECUTION;
93 er = ep->ExceptionRecord;
94 ctx = ep->ContextRecord;
95 sctx = g_malloc(sizeof(struct sigcontext));
97 /* Copy Win32 context to UNIX style context */
100 sctx->ecx = ctx->Ecx;
101 sctx->edx = ctx->Edx;
102 sctx->ebp = ctx->Ebp;
103 sctx->esp = ctx->Esp;
104 sctx->esi = ctx->Esi;
105 sctx->edi = ctx->Edi;
106 sctx->eip = ctx->Eip;
108 switch (er->ExceptionCode) {
109 case EXCEPTION_ACCESS_VIOLATION:
110 W32_SEH_HANDLE_EX(segv);
112 case EXCEPTION_ILLEGAL_INSTRUCTION:
113 W32_SEH_HANDLE_EX(ill);
115 case EXCEPTION_INT_DIVIDE_BY_ZERO:
116 case EXCEPTION_INT_OVERFLOW:
117 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
118 case EXCEPTION_FLT_OVERFLOW:
119 case EXCEPTION_FLT_UNDERFLOW:
120 case EXCEPTION_FLT_INEXACT_RESULT:
121 W32_SEH_HANDLE_EX(fpe);
127 /* Copy context back */
128 ctx->Eax = sctx->eax;
129 ctx->Ebx = sctx->ebx;
130 ctx->Ecx = sctx->ecx;
131 ctx->Edx = sctx->edx;
132 ctx->Ebp = sctx->ebp;
133 ctx->Esp = sctx->esp;
134 ctx->Esi = sctx->esi;
135 ctx->Edi = sctx->edi;
136 ctx->Eip = sctx->eip;
141 void win32_seh_init()
143 old_handler = SetUnhandledExceptionFilter(seh_handler);
146 void win32_seh_cleanup()
148 if (old_handler) SetUnhandledExceptionFilter(old_handler);
151 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
155 fpe_handler = handler;
158 ill_handler = handler;
161 segv_handler = handler;
168 #endif /* PLATFORM_WIN32 */
170 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
171 # define SC_EAX sc_eax
172 # define SC_EBX sc_ebx
173 # define SC_ECX sc_ecx
174 # define SC_EDX sc_edx
175 # define SC_EBP sc_ebp
176 # define SC_EIP sc_eip
177 # define SC_ESP sc_esp
178 # define SC_EDI sc_edi
179 # define SC_ESI sc_esi
192 gboolean mono_arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only);
194 typedef struct sigcontext MonoContext;
196 #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->SC_EIP = (long)ip; } while (0);
197 #define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->SC_EBP = (long)bp; } while (0);
199 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->SC_EIP))
200 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->SC_EBP))
202 #ifdef MONO_USE_EXC_TABLES
204 /*************************************/
205 /* STACK UNWINDING STUFF */
206 /*************************************/
208 /* These definitions are from unwind-dw2.c in glibc 2.2.5 */
211 #define DWARF_FRAME_REGISTERS 17
213 typedef struct frame_state
219 long reg_or_offset[DWARF_FRAME_REGISTERS+1];
220 unsigned short cfa_reg;
221 unsigned short retaddr_column;
222 char saved[DWARF_FRAME_REGISTERS+1];
226 get_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum)
228 switch (dwarf_regnum) {
246 g_assert_not_reached ();
253 set_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum, long value)
255 switch (dwarf_regnum) {
284 g_assert_not_reached ();
288 typedef struct frame_state * (*framesf) (void *, struct frame_state *);
290 static framesf frame_state_for = NULL;
292 static gboolean inited = FALSE;
294 typedef char ** (*get_backtrace_symbols_type) (void *__const *__array, int __size);
296 static get_backtrace_symbols_type get_backtrace_symbols = NULL;
299 init_frame_state_for (void)
304 * There are two versions of __frame_state_for: one in libgcc.a and the
305 * other in glibc.so. We need the version from glibc.
306 * For more info, see this:
307 * http://gcc.gnu.org/ml/gcc/2002-08/msg00192.html
309 if ((module = g_module_open ("libc.so.6", G_MODULE_BIND_LAZY))) {
311 if (!g_module_symbol (module, "__frame_state_for", (gpointer*)&frame_state_for))
312 frame_state_for = NULL;
314 if (!g_module_symbol (module, "backtrace_symbols", (gpointer*)&get_backtrace_symbols)) {
315 get_backtrace_symbols = NULL;
316 frame_state_for = NULL;
319 g_module_close (module);
325 /* mono_arch_has_unwind_info:
327 * Tests if a function has an DWARF exception table able to restore
328 * all caller saved registers.
331 mono_arch_has_unwind_info (gconstpointer addr)
333 struct frame_state state_in;
334 struct frame_state *res;
337 init_frame_state_for ();
339 if (!frame_state_for)
344 memset (&state_in, 0, sizeof (state_in));
346 /* offset 10 is just a guess, but it works for all methods tested */
347 if ((res = frame_state_for ((char *)addr + 10, &state_in))) {
349 if (res->saved [X86_EBX] == 1 &&
350 res->saved [X86_EDI] == 1 &&
351 res->saved [X86_EBP] == 1 &&
352 res->saved [X86_ESI] == 1)
362 void *return_address;
366 x86_unwind_native_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, struct sigcontext *ctx,
367 struct sigcontext *new_ctx, MonoLMF *lmf, char **trace)
369 struct stack_frame *frame;
372 struct frame_state state_in;
373 struct frame_state *res;
379 init_frame_state_for ();
381 if (!frame_state_for)
384 frame = MONO_CONTEXT_GET_BP (ctx);
386 max_stack = lmf && lmf->method ? lmf : jit_tls->end_of_stack;
390 memset (&state_in, 0, sizeof (state_in));
392 while ((gpointer)frame->next < (gpointer)max_stack) {
393 gpointer ip, addr = frame->return_address;
395 char *tmp, **symbols;
398 ip = MONO_CONTEXT_GET_IP (new_ctx);
399 symbols = get_backtrace_symbols (&ip, 1);
401 tmp = g_strdup_printf ("%s\nin (unmanaged) %s", *trace, symbols [0]);
403 tmp = g_strdup_printf ("in (unmanaged) %s", symbols [0]);
410 if ((res = frame_state_for (addr, &state_in))) {
413 cfa = (gint8*) (get_sigcontext_reg (new_ctx, res->cfa_reg) + res->cfa_offset);
414 frame = (struct stack_frame *)((gint8*)cfa - 8);
415 for (i = 0; i < DWARF_FRAME_REGISTERS + 1; i++) {
416 int how = res->saved[i];
418 g_assert ((how == 0) || (how == 1));
421 val = * (long*) ((gint8*)cfa + res->reg_or_offset[i]);
422 set_sigcontext_reg (new_ctx, i, val);
425 new_ctx->SC_ESP = (long)cfa;
427 if (res->saved [X86_EBX] == 1 &&
428 res->saved [X86_EDI] == 1 &&
429 res->saved [X86_EBP] == 1 &&
430 res->saved [X86_ESI] == 1 &&
431 (ji = mono_jit_info_table_find (domain, frame->return_address))) {
432 //printf ("FRAME CFA %s\n", mono_method_full_name (ji->method, TRUE));
437 //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)));
439 MONO_CONTEXT_SET_IP (new_ctx, frame->return_address);
441 MONO_CONTEXT_SET_BP (new_ctx, frame);
443 /* stop if !frame or when we detect an unexpected managed frame */
444 if (!frame || mono_jit_info_table_find (domain, frame->return_address)) {
455 //g_assert_not_reached ();
467 * arch_get_restore_context:
469 * Returns a pointer to a method which restores a previously saved sigcontext.
472 arch_get_restore_context (void)
474 static guint8 *start = NULL;
480 /* restore_contect (struct sigcontext *ctx) */
481 /* we do not restore X86_EAX, X86_EDX */
483 start = code = g_malloc (1024);
486 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
488 /* get return address, stored in EDX */
489 x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EIP), 4);
491 x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
493 x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
495 x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
497 x86_mov_reg_membase (code, X86_ESP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESP), 4);
499 x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
501 /* jump to the saved IP */
502 x86_jump_reg (code, X86_EDX);
508 * arch_get_call_filter:
510 * Returns a pointer to a method which calls an exception filter. We
511 * also use this function to call finally handlers (we pass NULL as
512 * @exc object in this case).
515 arch_get_call_filter (void)
517 static guint8 start [64];
518 static int inited = 0;
525 /* call_filter (struct sigcontext *ctx, unsigned long eip) */
528 x86_push_reg (code, X86_EBP);
529 x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
530 x86_push_reg (code, X86_EBX);
531 x86_push_reg (code, X86_EDI);
532 x86_push_reg (code, X86_ESI);
535 x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
537 x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
539 x86_push_reg (code, X86_EBP);
542 x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
543 /* restore registers used by global register allocation (EBX & ESI) */
544 x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
545 x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
546 x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
548 /* call the handler */
549 x86_call_reg (code, X86_ECX);
552 x86_pop_reg (code, X86_EBP);
554 /* restore saved regs */
555 x86_pop_reg (code, X86_ESI);
556 x86_pop_reg (code, X86_EDI);
557 x86_pop_reg (code, X86_EBX);
561 g_assert ((code - start) < 64);
566 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
567 unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
568 unsigned long eip, unsigned long esp)
570 static void (*restore_context) (struct sigcontext *);
571 struct sigcontext ctx;
573 if (!restore_context)
574 restore_context = arch_get_restore_context ();
576 /* adjust eip so that it point into the call instruction */
579 /* Pop argument and return address */
580 ctx.SC_ESP = esp + (2 * sizeof (gpointer));
590 mono_arch_handle_exception (&ctx, exc, FALSE);
591 restore_context (&ctx);
593 g_assert_not_reached ();
597 * arch_get_throw_exception:
599 * Returns a function pointer which can be used to raise
600 * exceptions. The returned function has the following
601 * signature: void (*func) (MonoException *exc);
602 * For example to raise an arithmetic exception you can use:
604 * x86_push_imm (code, mono_get_exception_arithmetic ());
605 * x86_call_code (code, arch_get_throw_exception ());
609 mono_arch_get_throw_exception (void)
611 static guint8 start [24];
612 static int inited = 0;
621 x86_push_reg (code, X86_ESP);
622 x86_push_membase (code, X86_ESP, 4); /* IP */
623 x86_push_membase (code, X86_ESP, 12); /* exception */
624 x86_push_reg (code, X86_EBP);
625 x86_push_reg (code, X86_EDI);
626 x86_push_reg (code, X86_ESI);
627 x86_push_reg (code, X86_EBX);
628 x86_push_reg (code, X86_EDX);
629 x86_push_reg (code, X86_ECX);
630 x86_push_reg (code, X86_EAX);
631 x86_call_code (code, throw_exception);
632 /* we should never reach this breakpoint */
633 x86_breakpoint (code);
635 g_assert ((code - start) < 24);
640 * arch_get_throw_exception_by_name:
642 * Returns a function pointer which can be used to raise
643 * corlib exceptions. The returned function has the following
644 * signature: void (*func) (char *exc_name);
645 * For example to raise an arithmetic exception you can use:
647 * x86_push_imm (code, "ArithmeticException");
648 * x86_call_code (code, arch_get_throw_exception_by_name ());
652 mono_arch_get_throw_exception_by_name (void)
654 static guint8 start [32];
655 static int inited = 0;
664 x86_push_membase (code, X86_ESP, 4); /* exception name */
665 x86_push_imm (code, "System");
666 x86_push_imm (code, mono_defaults.exception_class->image);
667 x86_call_code (code, mono_exception_from_name);
668 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
669 /* save the newly create object (overwrite exception name)*/
670 x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
671 x86_jump_code (code, mono_arch_get_throw_exception ());
673 g_assert ((code - start) < 32);
679 glist_to_array (GList *list)
681 MonoDomain *domain = mono_domain_get ();
688 len = g_list_length (list);
689 res = mono_array_new (domain, mono_defaults.int_class, len);
691 for (i = 0; list; list = list->next, i++)
692 mono_array_set (res, gpointer, i, list->data);
697 /* mono_arch_find_jit_info:
699 * This function is used to gather information from @ctx. It return the
700 * MonoJitInfo of the corresponding function, unwinds one stack frame and
701 * stores the resulting context into @new_ctx. It also stores a string
702 * describing the stack location into @trace (if not NULL), and modifies
703 * the @lmf if necessary. @native_offset return the IP offset from the
704 * start of the function or -1 if that info is not available.
707 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx,
708 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
712 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
714 /* Avoid costly table lookup during stack overflow */
715 if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
718 ji = mono_jit_info_table_find (domain, ip);
730 char *source_location, *tmpaddr, *fname;
731 gint32 address, iloffset;
736 address = (char *)ip - (char *)ji->code_start;
739 *native_offset = address;
742 if (!ji->method->wrapper_type)
746 source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
747 iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
750 tmpaddr = g_strdup_printf ("<0x%05x>", address);
752 tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
754 fname = mono_method_full_name (ji->method, TRUE);
757 *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
759 *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
762 g_free (source_location);
767 * Some managed methods like pinvoke wrappers might have save_lmf set.
768 * In this case, register save/restore code is not generated by the
769 * JIT, so we have to restore callee saved registers from the lmf.
771 if (ji->method->save_lmf) {
773 * We only need to do this if the exception was raised in managed
774 * code, since otherwise the lmf was already popped of the stack.
776 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
777 new_ctx->SC_ESI = (*lmf)->esi;
778 new_ctx->SC_EDI = (*lmf)->edi;
779 new_ctx->SC_EBX = (*lmf)->ebx;
784 /* restore caller saved registers */
785 if (ji->used_regs & X86_EBX_MASK) {
786 new_ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
789 if (ji->used_regs & X86_EDI_MASK) {
790 new_ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
793 if (ji->used_regs & X86_ESI_MASK) {
794 new_ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
798 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
799 /* remove any unused lmf */
800 *lmf = (*lmf)->previous_lmf;
803 /* Pop EBP and the return address */
804 new_ctx->SC_ESP = ctx->SC_EBP + (2 * sizeof (gpointer));
805 /* we substract 1, so that the IP points into the call instruction */
806 new_ctx->SC_EIP = *((int *)ctx->SC_EBP + 1) - 1;
807 new_ctx->SC_EBP = *((int *)ctx->SC_EBP);
811 #ifdef MONO_USE_EXC_TABLES
812 } else if ((ji = x86_unwind_native_frame (domain, jit_tls, ctx, new_ctx, *lmf, trace))) {
824 *trace = g_strdup_printf ("in (unmanaged) %s", mono_method_full_name ((*lmf)->method, TRUE));
826 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
829 memset (res, 0, sizeof (MonoJitInfo));
830 res->method = (*lmf)->method;
833 new_ctx->SC_ESI = (*lmf)->esi;
834 new_ctx->SC_EDI = (*lmf)->edi;
835 new_ctx->SC_EBX = (*lmf)->ebx;
836 new_ctx->SC_EBP = (*lmf)->ebp;
837 new_ctx->SC_EIP = (*lmf)->eip;
838 /* the lmf is always stored on the stack, so the following
839 * expression points to a stack location which can be used as ESP */
840 new_ctx->SC_ESP = (unsigned long)&((*lmf)->eip);
842 *lmf = (*lmf)->previous_lmf;
852 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
854 MonoDomain *domain = mono_domain_get ();
856 MonoArray *ta = exc->trace_ips;
860 /* Exception is not thrown yet */
861 return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
864 len = mono_array_length (ta);
866 res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
868 for (i = skip; i < len; i++) {
870 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
871 gpointer ip = mono_array_get (ta, gpointer, i);
873 ji = mono_jit_info_table_find (domain, ip);
875 /* Unmanaged frame */
876 mono_array_set (res, gpointer, i, sf);
880 g_assert (ji != NULL);
882 sf->method = mono_method_get_object (domain, ji->method, NULL);
883 sf->native_offset = (char *)ip - (char *)ji->code_start;
885 sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain);
887 if (need_file_info) {
890 filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
892 sf->filename = filename? mono_string_new (domain, filename): NULL;
898 mono_array_set (res, gpointer, i, sf);
905 mono_jit_walk_stack (MonoStackWalk func, gpointer user_data) {
906 MonoDomain *domain = mono_domain_get ();
907 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
908 MonoLMF *lmf = jit_tls->lmf;
909 MonoJitInfo *ji, rji;
910 gint native_offset, il_offset;
913 MonoContext ctx, new_ctx;
915 MONO_CONTEXT_SET_IP (&ctx, __builtin_return_address (0));
916 MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (1));
918 while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
920 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
923 if (ji == (gpointer)-1)
926 il_offset = mono_debug_il_offset_from_address (ji->method, native_offset, domain);
928 if (func (ji->method, native_offset, il_offset, managed, user_data))
936 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
937 MonoReflectionMethod **method,
938 gint32 *iloffset, gint32 *native_offset,
939 MonoString **file, gint32 *line, gint32 *column)
941 MonoDomain *domain = mono_domain_get ();
942 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
943 MonoLMF *lmf = jit_tls->lmf;
944 MonoJitInfo *ji, rji;
945 MonoContext ctx, new_ctx;
947 MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
948 MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (0));
953 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
957 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
960 /* skip all wrappers ??*/
961 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
962 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
963 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
970 *method = mono_method_get_object (domain, ji->method, NULL);
971 *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset, domain);
973 if (need_file_info) {
976 filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
978 *file = filename? mono_string_new (domain, filename): NULL;
988 * arch_handle_exception:
989 * @ctx: saved processor state
990 * @obj: the exception object
991 * @test_only: only test if the exception is caught, but dont call handlers
995 mono_arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
997 MonoDomain *domain = mono_domain_get ();
998 MonoJitInfo *ji, rji;
999 static int (*call_filter) (MonoContext *, gpointer) = NULL;
1000 static void (*restore_context) (struct sigcontext *);
1001 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1002 MonoLMF *lmf = jit_tls->lmf;
1003 GList *trace_ips = NULL;
1004 MonoException *mono_ex;
1005 gboolean stack_overflow = FALSE;
1006 MonoContext initial_ctx;
1007 int frame_count = 0;
1008 gboolean gc_disabled = FALSE;
1011 * This function might execute on an alternate signal stack, and Boehm GC
1012 * can't handle that.
1013 * Also, since the altstack is small, stack space intensive operations like
1014 * JIT compilation should be avoided.
1016 if (IS_ON_SIGALTSTACK (jit_tls)) {
1018 * FIXME: disabling/enabling GC while already on a signal stack might
1019 * not be safe either.
1021 /* Have to reenable it later */
1026 g_assert (ctx != NULL);
1028 MonoException *ex = mono_get_exception_null_reference ();
1029 ex->message = mono_string_new (domain, "Object reference not set to an instance of an object");
1030 obj = (MonoObject *)ex;
1033 if (mono_object_isinst (obj, mono_defaults.exception_class)) {
1034 mono_ex = (MonoException*)obj;
1035 mono_ex->stack_trace = NULL;
1040 if (obj == domain->stack_overflow_ex)
1041 stack_overflow = TRUE;
1044 call_filter = arch_get_call_filter ();
1046 if (!restore_context)
1047 restore_context = arch_get_restore_context ();
1049 g_assert (jit_tls->end_of_stack);
1050 g_assert (jit_tls->abort_func);
1053 MonoContext ctx_cp = *ctx;
1054 if (mono_jit_trace_calls != NULL)
1055 g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
1056 if (!mono_arch_handle_exception (&ctx_cp, obj, TRUE)) {
1057 if (mono_break_on_exc)
1059 mono_unhandled_exception (obj);
1064 memset (&rji, 0, sizeof (rji));
1067 MonoContext new_ctx;
1069 gboolean need_trace = FALSE;
1072 if (test_only && (frame_count < 1000))
1075 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx,
1076 need_trace ? &trace : NULL, &lmf, NULL, NULL);
1078 g_warning ("Exception inside function without unwind info");
1079 g_assert_not_reached ();
1082 if (ji != (gpointer)-1) {
1084 //printf ("M: %s %p %p %d.\n", mono_method_full_name (ji->method, TRUE), jit_tls->end_of_stack, ctx->ebp, count);
1086 if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
1089 /* Avoid giant stack traces */
1090 if (frame_count < 1000) {
1091 trace_ips = g_list_append (trace_ips, MONO_CONTEXT_GET_IP (ctx));
1093 if (!mono_ex->stack_trace)
1094 strace = g_strdup ("");
1096 strace = mono_string_to_utf8 (mono_ex->stack_trace);
1098 tmp = g_strdup_printf ("%s%s\n", strace, trace);
1101 mono_ex->stack_trace = mono_string_new (domain, tmp);
1108 free_stack = (guint8*)(MONO_CONTEXT_GET_BP (ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
1110 free_stack = 0xffffff;
1113 * During stack overflow, wait till the unwinding frees some stack
1114 * space before running handlers/finalizers.
1116 if ((free_stack > (64 * 1024)) && ji->num_clauses) {
1119 g_assert (ji->clauses);
1121 for (i = 0; i < ji->num_clauses; i++) {
1122 MonoJitExceptionInfo *ei = &ji->clauses [i];
1124 if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
1125 MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) {
1128 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
1129 /* store the exception object int cfg->excvar */
1130 g_assert (ji->exvar_offset);
1131 *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
1134 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
1135 mono_object_isinst (obj, mono_class_get (ji->method->klass->image, ei->data.token))) ||
1136 ((ei->flags == MONO_EXCEPTION_CLAUSE_FILTER &&
1137 call_filter (ctx, ei->data.filter)))) {
1140 mono_ex->trace_ips = glist_to_array (trace_ips);
1141 g_list_free (trace_ips);
1148 if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
1149 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1150 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
1158 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
1159 MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
1160 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
1161 if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
1162 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
1163 call_filter (ctx, ei->handler_start);
1175 if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
1182 if (IS_ON_SIGALTSTACK (jit_tls)) {
1183 /* Switch back to normal stack */
1185 /* Free up some stack space */
1186 initial_ctx.SC_ESP += (64 * 1024);
1187 initial_ctx.SC_EIP = (unsigned int)jit_tls->abort_func;
1188 restore_context (&initial_ctx);
1191 jit_tls->abort_func (obj);
1192 g_assert_not_reached ();
1195 mono_ex->trace_ips = glist_to_array (trace_ips);
1196 g_list_free (trace_ips);
1202 g_assert_not_reached ();