2 * exception.c: exception support
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2001 Ximian, Inc.
16 #include <mono/arch/ppc/ppc-codegen.h>
17 #include <mono/metadata/appdomain.h>
18 #include <mono/metadata/tabledefs.h>
19 #include <mono/metadata/threads.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/mono-debug.h>
27 typedef struct sigcontext MonoContext;
32 int sc_onstack; // sigstack state to restore
33 int sc_mask; // signal mask to restore
35 int sc_psw; // processor status word
36 int sc_sp; // stack pointer if sc_regs == NULL
37 void *sc_regs; // (kernel private) saved state
42 sigset_t uc_sigmask; // signal mask used by this context
43 stack_t uc_stack; // stack used by this context
44 struct ucontext *uc_link; // pointer to resuming context
45 size_t uc_mcsize; // size of the machine context passed in
46 mcontext_t uc_mcontext; // machine specific context
49 typedef struct ppc_exception_state {
50 unsigned long dar; // Fault registers for coredump
52 unsigned long exception;// number of powerpc exception taken
53 unsigned long pad0; // align to 16 bytes
55 unsigned long pad1[4]; // space in PCB "just in case"
56 } ppc_exception_state_t;
58 typedef struct ppc_vector_state {
59 unsigned long save_vr[32][4];
60 unsigned long save_vscr[4];
61 unsigned int save_pad5[4];
62 unsigned int save_vrvalid; // VRs that have been saved
63 unsigned int save_pad6[7];
66 typedef struct ppc_float_state {
69 unsigned int fpscr_pad; // fpscr is 64 bits, 32 bits of rubbish
70 unsigned int fpscr; // floating point status register
73 typedef struct ppc_thread_state {
74 unsigned int srr0; // Instruction address register (PC)
75 unsigned int srr1; // Machine state register (supervisor)
81 unsigned int cr; // Condition register
82 unsigned int xer; // User's integer exception register
83 unsigned int lr; // Link register
84 unsigned int ctr; // Count register
85 unsigned int mq; // MQ register (601 only)
87 unsigned int vrsave; // Vector Save Register
91 ppc_exception_state_t es;
92 ppc_thread_state_t ss;
94 ppc_vector_state_t vs;
97 typedef struct mcontext * mcontext_t;
101 /* we have the stack pointer, not the base pointer in sigcontext */
102 #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->sc_ir = (int)ip; } while (0);
103 #define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->sc_sp = (int)bp; } while (0);
105 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->sc_ir))
106 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->sc_sp))
108 /* disbale this for now */
109 #undef MONO_USE_EXC_TABLES
111 #ifdef MONO_USE_EXC_TABLES
113 /*************************************/
114 /* STACK UNWINDING STUFF */
115 /*************************************/
117 /* These definitions are from unwind-dw2.c in glibc 2.2.5 */
120 #define DWARF_FRAME_REGISTERS 17
122 typedef struct frame_state
128 long reg_or_offset[DWARF_FRAME_REGISTERS+1];
129 unsigned short cfa_reg;
130 unsigned short retaddr_column;
131 char saved[DWARF_FRAME_REGISTERS+1];
137 get_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum)
139 switch (dwarf_regnum) {
157 g_assert_not_reached ();
164 set_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum, long value)
166 switch (dwarf_regnum) {
195 g_assert_not_reached ();
199 typedef struct frame_state * (*framesf) (void *, struct frame_state *);
201 static framesf frame_state_for = NULL;
203 static gboolean inited = FALSE;
205 typedef char ** (*get_backtrace_symbols_type) (void *__const *__array, int __size);
207 static get_backtrace_symbols_type get_backtrace_symbols = NULL;
210 init_frame_state_for (void)
215 * There are two versions of __frame_state_for: one in libgcc.a and the
216 * other in glibc.so. We need the version from glibc.
217 * For more info, see this:
218 * http://gcc.gnu.org/ml/gcc/2002-08/msg00192.html
220 if ((module = g_module_open ("libc.so.6", G_MODULE_BIND_LAZY))) {
222 if (!g_module_symbol (module, "__frame_state_for", (gpointer*)&frame_state_for))
223 frame_state_for = NULL;
225 if (!g_module_symbol (module, "backtrace_symbols", (gpointer*)&get_backtrace_symbols)) {
226 get_backtrace_symbols = NULL;
227 frame_state_for = NULL;
230 g_module_close (module);
238 gboolean mono_arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only);
240 /* mono_arch_has_unwind_info:
242 * Tests if a function has an DWARF exception table able to restore
243 * all caller saved registers.
246 mono_arch_has_unwind_info (MonoMethod *method)
249 struct frame_state state_in;
250 struct frame_state *res;
253 init_frame_state_for ();
255 if (!frame_state_for)
258 g_assert (method->addr);
260 memset (&state_in, 0, sizeof (state_in));
262 /* offset 10 is just a guess, but it works for all methods tested */
263 if ((res = frame_state_for ((char *)method->addr + 10, &state_in))) {
265 if (res->saved [X86_EBX] != 1 ||
266 res->saved [X86_EDI] != 1 ||
267 res->saved [X86_EBP] != 1 ||
268 res->saved [X86_ESI] != 1) {
283 void *return_address;
287 ppc_unwind_native_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, struct sigcontext *ctx,
288 struct sigcontext *new_ctx, MonoLMF *lmf, char **trace)
291 struct stack_frame *frame;
294 struct frame_state state_in;
295 struct frame_state *res;
301 init_frame_state_for ();
303 if (!frame_state_for)
306 frame = MONO_CONTEXT_GET_BP (ctx);
308 max_stack = lmf && lmf->method ? lmf : jit_tls->end_of_stack;
312 memset (&state_in, 0, sizeof (state_in));
314 while ((gpointer)frame->next < (gpointer)max_stack) {
315 gpointer ip, addr = frame->return_address;
317 char *tmp, **symbols;
320 ip = MONO_CONTEXT_GET_IP (new_ctx);
321 symbols = get_backtrace_symbols (&ip, 1);
323 tmp = g_strdup_printf ("%s\nin (unmanaged) %s", *trace, symbols [0]);
325 tmp = g_strdup_printf ("in (unmanaged) %s", symbols [0]);
332 if ((res = frame_state_for (addr, &state_in))) {
335 cfa = (gint8*) (get_sigcontext_reg (new_ctx, res->cfa_reg) + res->cfa_offset);
336 frame = (struct stack_frame *)((gint8*)cfa - 8);
337 for (i = 0; i < DWARF_FRAME_REGISTERS + 1; i++) {
338 int how = res->saved[i];
340 g_assert ((how == 0) || (how == 1));
343 val = * (long*) ((gint8*)cfa + res->reg_or_offset[i]);
344 set_sigcontext_reg (new_ctx, i, val);
347 new_ctx->SC_ESP = (long)cfa;
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 &&
353 (ji = mono_jit_info_table_find (domain, frame->return_address))) {
354 //printf ("FRAME CFA %s\n", mono_method_full_name (ji->method, TRUE));
359 //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)));
361 MONO_CONTEXT_SET_IP (new_ctx, frame->return_address);
363 MONO_CONTEXT_SET_BP (new_ctx, frame);
365 /* stop if !frame or when we detect an unexpected managed frame */
366 if (!frame || mono_jit_info_table_find (domain, frame->return_address)) {
377 //g_assert_not_reached ();
390 * arch_get_restore_context:
392 * Returns a pointer to a method which restores a previously saved sigcontext.
395 arch_get_restore_context (void)
397 static guint8 *start = NULL;
404 /* restore_contect (struct sigcontext *ctx) */
405 /* we do not restore X86_EAX, X86_EDX */
407 start = code = g_malloc (1024);
410 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
412 /* get return address, stored in EDX */
413 x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EIP), 4);
415 x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
417 x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
419 x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
421 x86_mov_reg_membase (code, X86_ESP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESP), 4);
423 x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
425 /* jump to the saved IP */
426 x86_jump_reg (code, X86_EDX);
433 * arch_get_call_filter:
435 * Returns a pointer to a method which calls an exception filter. We
436 * also use this function to call finally handlers (we pass NULL as
437 * @exc object in this case).
440 arch_get_call_filter (void)
442 static guint8 start [64];
443 static int inited = 0;
450 /* call_filter (struct sigcontext *ctx, unsigned long eip, gpointer exc) */
454 x86_push_reg (code, X86_EBP);
455 x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
456 x86_push_reg (code, X86_EBX);
457 x86_push_reg (code, X86_EDI);
458 x86_push_reg (code, X86_ESI);
461 x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
463 x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
465 x86_push_reg (code, X86_EBP);
467 x86_push_membase (code, X86_EBP, 16);
469 x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
470 /* restore registers used by global register allocation (EBX & ESI) */
471 x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
472 x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
473 x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
474 /* save the ESP - this is used by endfinally */
475 x86_mov_membase_reg (code, X86_EBP, mono_exc_esp_offset, X86_ESP, 4);
476 /* call the handler */
477 x86_call_reg (code, X86_ECX);
478 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
480 x86_pop_reg (code, X86_EBP);
481 /* restore saved regs */
482 x86_pop_reg (code, X86_ESI);
483 x86_pop_reg (code, X86_EDI);
484 x86_pop_reg (code, X86_EBX);
488 g_assert ((code - start) < 64);
494 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
495 unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
496 unsigned long eip, unsigned long esp)
498 static void (*restore_context) (struct sigcontext *);
499 struct sigcontext ctx;
501 if (!restore_context)
502 restore_context = arch_get_restore_context ();
504 /* adjust eip so that it point into the call instruction */
518 mono_arch_handle_exception (&ctx, exc, FALSE);
519 restore_context (&ctx);
521 g_assert_not_reached ();
525 * arch_get_throw_exception:
527 * Returns a function pointer which can be used to raise
528 * exceptions. The returned function has the following
529 * signature: void (*func) (MonoException *exc);
530 * For example to raise an arithmetic exception you can use:
532 * x86_push_imm (code, mono_get_exception_arithmetic ());
533 * x86_call_code (code, arch_get_throw_exception ());
537 mono_arch_get_throw_exception (void)
539 static guint8 start [24];
540 static int inited = 0;
550 x86_push_reg (code, X86_ESP);
551 x86_push_membase (code, X86_ESP, 4); /* IP */
552 x86_push_membase (code, X86_ESP, 12); /* exception */
553 x86_push_reg (code, X86_EBP);
554 x86_push_reg (code, X86_EDI);
555 x86_push_reg (code, X86_ESI);
556 x86_push_reg (code, X86_EBX);
557 x86_push_reg (code, X86_EDX);
558 x86_push_reg (code, X86_ECX);
559 x86_push_reg (code, X86_EAX);
560 x86_call_code (code, throw_exception);
561 /* we should never reach this breakpoint */
562 x86_breakpoint (code);
564 g_assert ((code - start) < 24);
570 * arch_get_throw_exception_by_name:
572 * Returns a function pointer which can be used to raise
573 * corlib exceptions. The returned function has the following
574 * signature: void (*func) (char *exc_name);
575 * For example to raise an arithmetic exception you can use:
577 * x86_push_imm (code, "ArithmeticException");
578 * x86_call_code (code, arch_get_throw_exception_by_name ());
582 mono_arch_get_throw_exception_by_name (void)
584 static guint8 start [32];
585 static int inited = 0;
594 x86_push_membase (code, X86_ESP, 4); /* exception name */
595 x86_push_imm (code, "System");
596 x86_push_imm (code, mono_defaults.exception_class->image);
597 x86_call_code (code, mono_exception_from_name);
598 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
599 /* save the newly create object (overwrite exception name)*/
600 x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
601 x86_jump_code (code, mono_arch_get_throw_exception ());
603 g_assert ((code - start) < 32);
609 glist_to_array (GList *list)
611 MonoDomain *domain = mono_domain_get ();
618 len = g_list_length (list);
619 res = mono_array_new (domain, mono_defaults.int_class, len);
621 for (i = 0; list; list = list->next, i++)
622 mono_array_set (res, gpointer, i, list->data);
627 /* mono_arch_find_jit_info:
629 * This function is used to gather information from @ctx. It return the
630 * MonoJitInfo of the corresponding function, unwinds one stack frame and
631 * stores the resulting context into @new_ctx. It also stores a string
632 * describing the stack location into @trace (if not NULL), and modifies
633 * the @lmf if necessary. @native_offset return the IP offset from the
634 * start of the function or -1 if that info is not available.
637 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoContext *ctx,
638 MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
642 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
644 ji = mono_jit_info_table_find (domain, ip);
656 char *source_location, *tmpaddr, *fname;
657 gint32 address, iloffset;
662 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
663 /* remove any unused lmf */
664 *lmf = (*lmf)->previous_lmf;
667 address = (char *)ip - (char *)ji->code_start;
670 *native_offset = address;
673 if (!ji->method->wrapper_type)
677 source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
678 iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
681 tmpaddr = g_strdup_printf ("<0x%05x>", address);
683 tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
685 fname = mono_method_full_name (ji->method, TRUE);
688 *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
690 *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
693 g_free (source_location);
698 /* restore caller saved registers */
699 if (ji->used_regs & X86_EBX_MASK) {
700 new_ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
703 if (ji->used_regs & X86_EDI_MASK) {
704 new_ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
707 if (ji->used_regs & X86_ESI_MASK) {
708 new_ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
711 new_ctx->SC_ESP = ctx->SC_EBP;
712 /* we substract 1, so that the IP points into the call instruction */
713 new_ctx->SC_EIP = *((int *)ctx->SC_EBP + 1) - 1;
714 new_ctx->SC_EBP = *((int *)ctx->SC_EBP);
718 #ifdef MONO_USE_EXC_TABLES
719 } else if ((ji = ppc_unwind_native_frame (domain, jit_tls, ctx, new_ctx, *lmf, trace))) {
731 *trace = g_strdup_printf ("in (unmanaged) %s", mono_method_full_name ((*lmf)->method, TRUE));
733 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
736 memset (res, 0, sizeof (MonoJitInfo));
737 res->method = (*lmf)->method;
741 new_ctx->SC_ESI = (*lmf)->esi;
742 new_ctx->SC_EDI = (*lmf)->edi;
743 new_ctx->SC_EBX = (*lmf)->ebx;
744 new_ctx->SC_EBP = (*lmf)->ebp;
745 new_ctx->SC_EIP = (*lmf)->eip;
746 /* the lmf is always stored on the stack, so the following
747 * expression points to a stack location which can be used as ESP */
748 new_ctx->SC_ESP = (unsigned long)&((*lmf)->eip);
750 *lmf = (*lmf)->previous_lmf;
760 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
762 MonoDomain *domain = mono_domain_get ();
764 MonoArray *ta = exc->trace_ips;
767 len = mono_array_length (ta);
769 res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
771 for (i = skip; i < len; i++) {
773 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
774 gpointer ip = mono_array_get (ta, gpointer, i);
776 ji = mono_jit_info_table_find (domain, ip);
777 g_assert (ji != NULL);
779 sf->method = mono_method_get_object (domain, ji->method, NULL);
780 sf->native_offset = (char *)ip - (char *)ji->code_start;
782 sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain);
784 if (need_file_info) {
787 filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
789 sf->filename = filename? mono_string_new (domain, filename): NULL;
795 mono_array_set (res, gpointer, i, sf);
802 mono_jit_walk_stack (MonoStackWalk func, gpointer user_data) {
803 MonoDomain *domain = mono_domain_get ();
804 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
805 MonoLMF *lmf = jit_tls->lmf;
806 MonoJitInfo *ji, rji;
807 gint native_offset, il_offset;
810 MonoContext ctx, new_ctx;
812 MONO_CONTEXT_SET_IP (&ctx, __builtin_return_address (0));
813 MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (1));
815 while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
817 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
820 if (ji == (gpointer)-1)
823 il_offset = mono_debug_il_offset_from_address (ji->method, native_offset, domain);
825 if (func (ji->method, native_offset, il_offset, managed, user_data))
833 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
834 MonoReflectionMethod **method,
835 gint32 *iloffset, gint32 *native_offset,
836 MonoString **file, gint32 *line, gint32 *column)
838 MonoDomain *domain = mono_domain_get ();
839 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
840 MonoLMF *lmf = jit_tls->lmf;
841 MonoJitInfo *ji, rji;
842 MonoContext ctx, new_ctx;
844 MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
845 MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (0));
850 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
854 if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
857 /* skip all wrappers ??*/
858 if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
859 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
860 ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE)
867 *method = mono_method_get_object (domain, ji->method, NULL);
868 *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset, domain);
870 if (need_file_info) {
873 filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
875 *file = filename? mono_string_new (domain, filename): NULL;
885 * arch_handle_exception:
886 * @ctx: saved processor state
887 * @obj: the exception object
888 * @test_only: only test if the exception is caught, but dont call handlers
893 mono_arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
895 MonoDomain *domain = mono_domain_get ();
896 MonoJitInfo *ji, rji;
897 static int (*call_filter) (MonoContext *, gpointer, gpointer) = NULL;
898 MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
899 MonoLMF *lmf = jit_tls->lmf;
900 GList *trace_ips = NULL;
902 g_assert (ctx != NULL);
904 MonoException *ex = mono_get_exception_null_reference ();
905 ex->message = mono_string_new (domain,
906 "Object reference not set to an instance of an object");
907 obj = (MonoObject *)ex;
910 g_assert (mono_object_isinst (obj, mono_defaults.exception_class));
913 call_filter = arch_get_call_filter ();
915 g_assert (jit_tls->end_of_stack);
916 g_assert (jit_tls->abort_func);
919 MonoContext ctx_cp = *ctx;
920 if (mono_jit_trace_calls)
921 g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
922 if (!mono_arch_handle_exception (&ctx_cp, obj, TRUE)) {
923 if (mono_break_on_exc)
925 mono_unhandled_exception (obj);
933 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, ctx, &new_ctx,
934 test_only ? &trace : NULL, &lmf, NULL, NULL);
936 g_warning ("Exception inside function without unwind info");
937 g_assert_not_reached ();
940 if (ji != (gpointer)-1) {
942 if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
945 trace_ips = g_list_append (trace_ips, MONO_CONTEXT_GET_IP (ctx));
947 if (!((MonoException*)obj)->stack_trace)
948 strace = g_strdup ("");
950 strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
952 tmp = g_strdup_printf ("%s%s\n", strace, trace);
955 ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
960 if (ji->num_clauses) {
963 g_assert (ji->clauses);
965 for (i = 0; i < ji->num_clauses; i++) {
966 MonoJitExceptionInfo *ei = &ji->clauses [i];
968 if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
969 MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) {
971 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE &&
972 mono_object_isinst (obj, mono_class_get (ji->method->klass->image, ei->data.token))) ||
973 ((ei->flags == MONO_EXCEPTION_CLAUSE_FILTER &&
974 call_filter (ctx, ei->data.filter, obj)))) {
976 ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
977 g_list_free (trace_ips);
981 if (mono_jit_trace_calls)
982 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
983 MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
984 *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
989 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) &&
990 MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
991 (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
992 if (mono_jit_trace_calls)
993 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
994 call_filter (ctx, ei->handler_start, NULL);
1006 if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
1009 jit_tls->abort_func (obj);
1010 g_assert_not_reached ();
1012 ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
1013 g_list_free (trace_ips);
1019 g_assert_not_reached ();
1023 mono_arch_has_unwind_info (gconstpointer addr)